blob: e5ca4ff389fcbfe660fa3573d493d8a22033200f [file] [log] [blame]
/*
*
* Copyright (c) 2021 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.
*/
#include <protocols/secure_channel/CASEServer.h>
#include <core/CHIPError.h>
#include <support/CodeUtils.h>
#include <support/SafeInt.h>
#include <support/logging/CHIPLogging.h>
#include <transport/SecureSessionMgr.h>
using namespace ::chip::Inet;
using namespace ::chip::Transport;
using namespace ::chip::Credentials;
namespace chip {
CHIP_ERROR CASEServer::ListenForSessionEstablishment(Messaging::ExchangeManager * exchangeManager, TransportMgrBase * transportMgr,
SecureSessionMgr * sessionMgr, Transport::FabricTable * fabrics,
SessionIDAllocator * idAllocator)
{
VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(sessionMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(fabrics != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
mSessionMgr = sessionMgr;
mFabrics = fabrics;
mExchangeManager = exchangeManager;
mIDAllocator = idAllocator;
Cleanup();
ReturnErrorOnFailure(GetSession().MessageDispatch().Init(transportMgr));
return CHIP_NO_ERROR;
}
CHIP_ERROR CASEServer::InitCASEHandshake(Messaging::ExchangeContext * ec)
{
ReturnErrorCodeIf(ec == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
// TODO - Use section [4.368] and definition of `Destination Identifier` to find fabric ID for CASE SigmaR1 message
mFabricIndex = kMinValidFabricIndex;
Transport::FabricInfo * fabric = mFabrics->FindFabricWithIndex(mFabricIndex);
ReturnErrorCodeIf(fabric == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
if (!fabric->IsInitialized() || !fabric->AreCredentialsAvailable())
{
ReturnErrorOnFailure(mFabrics->LoadFromStorage(mFabricIndex));
fabric = mFabrics->FindFabricWithIndex(mFabricIndex);
}
ReturnErrorCodeIf(fabric == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
uint8_t credentialsIndex;
ReturnErrorOnFailure(fabric->GetCredentials(mCredentials, mCertificates, mRootKeyId, credentialsIndex));
ReturnErrorOnFailure(mIDAllocator->Allocate(mSessionKeyId));
// Setup CASE state machine using the credentials for the current fabric.
ReturnErrorOnFailure(GetSession().ListenForSessionEstablishment(&mCredentials, mSessionKeyId, this));
// Hand over the exchange context to the CASE session.
ec->SetDelegate(&GetSession());
return CHIP_NO_ERROR;
}
CHIP_ERROR CASEServer::OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader,
const PayloadHeader & payloadHeader, System::PacketBufferHandle && payload)
{
ChipLogProgress(Inet, "CASE Server received SigmaR1 message. Starting handshake. EC %p", ec);
CHIP_ERROR err = InitCASEHandshake(ec);
SuccessOrExit(err);
// TODO - Enable multiple concurrent CASE session establishment
// https://github.com/project-chip/connectedhomeip/issues/8342
ChipLogProgress(Inet, "CASE Server disabling CASE session setups");
mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1);
err = GetSession().OnMessageReceived(ec, packetHeader, payloadHeader, std::move(payload));
SuccessOrExit(err);
exit:
if (err != CHIP_NO_ERROR)
{
Cleanup();
}
return err;
}
void CASEServer::Cleanup()
{
// Let's re-register for CASE SigmaR1 message, so that the next CASE session setup request can be processed.
// https://github.com/project-chip/connectedhomeip/issues/8342
ChipLogProgress(Inet, "CASE Server enabling CASE session setups");
mExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1, this);
mFabricIndex = Transport::kUndefinedFabricIndex;
mCredentials.Release();
mCertificates.Release();
GetSession().Clear();
}
void CASEServer::OnSessionEstablishmentError(CHIP_ERROR err)
{
ChipLogProgress(Inet, "CASE Session establishment failed: %s", ErrorStr(err));
mIDAllocator->Free(mSessionKeyId);
Cleanup();
}
void CASEServer::OnSessionEstablished()
{
ChipLogProgress(Inet, "CASE Session established. Setting up the secure channel.");
mSessionMgr->ExpireAllPairings(GetSession().PeerConnection().GetPeerNodeId(), mFabricIndex);
CHIP_ERROR err = mSessionMgr->NewPairing(
Optional<Transport::PeerAddress>::Value(GetSession().PeerConnection().GetPeerAddress()),
GetSession().PeerConnection().GetPeerNodeId(), &GetSession(), SecureSession::SessionRole::kResponder, mFabricIndex);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Inet, "Failed in setting up secure channel: err %s", ErrorStr(err));
OnSessionEstablishmentError(err);
return;
}
ChipLogProgress(Inet, "CASE secure channel is available now.");
Cleanup();
}
} // namespace chip