Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable CASE session establishment #7666

Merged
merged 12 commits into from
Jun 23, 2021
25 changes: 20 additions & 5 deletions examples/chip-tool/commands/clusters/ModelCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ CHIP_ERROR ModelCommand::Run(NodeId localId, NodeId remoteId)
{
chip::DeviceLayer::StackLock lock;

err = GetExecContext()->commissioner->GetDevice(remoteId, &mDevice);
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(chipTool, "Init failure! No pairing for device: %" PRIu64, localId));

err = SendCommand(mDevice, mEndPointId);
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(chipTool, "Failed to send message: %s", ErrorStr(err)));
err = GetExecContext()->commissioner->GetConnectedDevice(remoteId, &mOnDeviceConnectedCallback,
&mOnDeviceConnectionFailureCallback);
VerifyOrExit(err == CHIP_NO_ERROR,
ChipLogError(chipTool, "Failed in initiating connection to the device: %" PRIu64 ", error %d", remoteId, err));
}

WaitForResponse(kWaitDurationInSeconds);
Expand All @@ -65,3 +64,19 @@ CHIP_ERROR ModelCommand::Run(NodeId localId, NodeId remoteId)
exit:
return err;
}

void ModelCommand::OnDeviceConnectedFn(void * context, chip::Controller::Device * device)
{
ModelCommand * command = reinterpret_cast<ModelCommand *>(context);
VerifyOrReturn(command != nullptr,
ChipLogError(chipTool, "Device connected, but cannot send the command, as the context is null"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this happen (how)?

If not suggest VerifyOrDie(command != nullptr) or just leave it off since it's obvious anyway due to the call below.

command->SendCommand(device, command->mEndPointId);
}

void ModelCommand::OnDeviceConnectionFailureFn(void * context, NodeId deviceId, CHIP_ERROR error)
{
ModelCommand * command = reinterpret_cast<ModelCommand *>(context);
ChipLogError(chipTool, "Failed in connecting to the device %" PRIu64 ". Error %d", deviceId, error);
VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "ModelCommand context is null"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VerifyOrDie(command != nullptr) here too.

command->SetCommandExitStatus(false);
}
12 changes: 10 additions & 2 deletions examples/chip-tool/commands/clusters/ModelCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
class ModelCommand : public Command
{
public:
ModelCommand(const char * commandName) : Command(commandName) {}
ModelCommand(const char * commandName) :
Command(commandName), mOnDeviceConnectedCallback(OnDeviceConnectedFn, this),
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{}

void AddArguments() { AddArgument("endpoint-id", CHIP_ZCL_ENDPOINT_MIN, CHIP_ZCL_ENDPOINT_MAX, &mEndPointId); }

Expand All @@ -41,6 +44,11 @@ class ModelCommand : public Command
virtual CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endPointId) = 0;

private:
ChipDevice * mDevice;
uint8_t mEndPointId;

static void OnDeviceConnectedFn(void * context, chip::Controller::Device * device);
static void OnDeviceConnectionFailureFn(void * context, NodeId deviceId, CHIP_ERROR error);

chip::Callback::Callback<chip::Controller::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::Controller::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
};
4 changes: 1 addition & 3 deletions examples/chip-tool/commands/discover/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,8 @@ class Update : public DiscoverCommand
/////////// DiscoverCommand Interface /////////
CHIP_ERROR RunCommand(NodeId remoteId, uint64_t fabricId) override
{
ChipDevice * device;
ReturnErrorOnFailure(GetExecContext()->commissioner->GetDevice(remoteId, &device));
ChipLogProgress(chipTool, "Mdns: Updating NodeId: %" PRIx64 " FabricId: %" PRIx64 " ...", remoteId, fabricId);
return GetExecContext()->commissioner->UpdateDevice(device, fabricId);
return GetExecContext()->commissioner->UpdateDevice(remoteId, fabricId);
}

/////////// DeviceAddressUpdateDelegate Interface /////////
Expand Down
24 changes: 21 additions & 3 deletions examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ void PairingCommand::OnPairingDeleted(CHIP_ERROR err)
SetCommandExitStatus(err == CHIP_NO_ERROR);
}

void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
{
if (err == CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "Device commissioning completed with success");
}
else
{
ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
}

SetCommandExitStatus(err == CHIP_NO_ERROR);
}

CHIP_ERROR PairingCommand::SetupNetwork()
{

Expand Down Expand Up @@ -316,13 +330,17 @@ void PairingCommand::OnEnableNetworkResponse(void * context, uint8_t errorCode,

CHIP_ERROR PairingCommand::UpdateNetworkAddress()
{
ReturnErrorOnFailure(GetExecContext()->commissioner->GetDevice(mRemoteId, &mDevice));
ChipLogProgress(chipTool, "Mdns: Updating NodeId: %" PRIx64 " FabricId: %" PRIx64 " ...", mRemoteId, mFabricId);
return GetExecContext()->commissioner->UpdateDevice(mDevice, mFabricId);
return GetExecContext()->commissioner->UpdateDevice(mRemoteId, mFabricId);
}

void PairingCommand::OnAddressUpdateComplete(NodeId nodeId, CHIP_ERROR err)
{
ChipLogProgress(chipTool, "OnAddressUpdateComplete: %s", ErrorStr(err));
SetCommandExitStatus(CHIP_NO_ERROR == err);
if (err != CHIP_NO_ERROR)
{
// Set exit status only if the address update failed.
// Otherwise wait for OnCommissioningComplete() callback.
SetCommandExitStatus(false);
}
}
1 change: 1 addition & 0 deletions examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class PairingCommand : public Command,
void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error) override;
void OnPairingDeleted(CHIP_ERROR error) override;
void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override;

/////////// DeviceAddressUpdateDelegate Interface /////////
void OnAddressUpdateComplete(NodeId nodeId, CHIP_ERROR error) override;
Expand Down
15 changes: 12 additions & 3 deletions src/app/server/RendezvousServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,18 @@ CHIP_ERROR RendezvousServer::WaitForPairing(const RendezvousParameters & params,
ReturnErrorOnFailure(mExchangeManager->RegisterUnsolicitedMessageHandlerForType(
Protocols::SecureChannel::MsgType::PBKDFParamRequest, &mPairingSession));

uint16_t keyID = 0;
ReturnErrorOnFailure(mIDAllocator->Allocate(keyID));

if (params.HasPASEVerifier())
{
ReturnErrorOnFailure(mPairingSession.WaitForPairing(params.GetPASEVerifier(), mNextKeyId++, this));
ReturnErrorOnFailure(mPairingSession.WaitForPairing(params.GetPASEVerifier(), keyID, this));
}
else
{
ReturnErrorOnFailure(mPairingSession.WaitForPairing(params.GetSetupPINCode(), kSpake2p_Iteration_Count,
reinterpret_cast<const unsigned char *>(kSpake2pKeyExchangeSalt),
strlen(kSpake2pKeyExchangeSalt), mNextKeyId++, this));
strlen(kSpake2pKeyExchangeSalt), keyID, this));
}

ReturnErrorOnFailure(mPairingSession.MessageDispatch().Init(transportMgr));
Expand Down Expand Up @@ -181,6 +184,12 @@ void RendezvousServer::OnSessionEstablished()
VerifyOrReturn(connection.StoreIntoKVS(*mStorage) == CHIP_NO_ERROR,
ChipLogError(AppServer, "Failed to store the connection state"));

mStorage->SyncSetKeyValue(kStorablePeerConnectionCountKey, &mNextKeyId, sizeof(mNextKeyId));
// The Peek() is used to find the smallest key ID that's not been assigned to any session.
// This value is persisted, and on reboot, it is used to revive any previously
// active secure sessions.
// We support one active PASE session at any time. So the key ID should not be updated
// in another thread, while we retrieve it here.
uint16_t keyID = mIDAllocator->Peek();
mStorage->SyncSetKeyValue(kStorablePeerConnectionCountKey, &keyID, sizeof(keyID));
}
} // namespace chip
16 changes: 11 additions & 5 deletions src/app/server/RendezvousServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <messaging/ExchangeMgr.h>
#include <platform/CHIPDeviceLayer.h>
#include <protocols/secure_channel/RendezvousParameters.h>
#include <protocols/secure_channel/SessionIDAllocator.h>

namespace chip {

Expand All @@ -31,11 +32,17 @@ class RendezvousServer : public SessionEstablishmentDelegate
CHIP_ERROR WaitForPairing(const RendezvousParameters & params, Messaging::ExchangeManager * exchangeManager,
TransportMgrBase * transportMgr, SecureSessionMgr * sessionMgr, Transport::AdminPairingInfo * admin);

CHIP_ERROR Init(AppDelegate * delegate, PersistentStorageDelegate * storage)
CHIP_ERROR Init(AppDelegate * delegate, PersistentStorageDelegate * storage, SessionIDAllocator * idAllocator)
{
VerifyOrReturnError(storage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
mStorage = storage;

VerifyOrReturnError(idAllocator != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
mIDAllocator = idAllocator;
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

// The caller may chose to not provide a delegate object. The RendezvousServer checks for null delegate before calling
// its methods.
mDelegate = delegate;
mStorage = storage;
return CHIP_NO_ERROR;
}

Expand All @@ -45,8 +52,6 @@ class RendezvousServer : public SessionEstablishmentDelegate

void Cleanup();

uint16_t GetNextKeyId() const { return mNextKeyId; }
void SetNextKeyId(uint16_t id) { mNextKeyId = id; }
void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event);

private:
Expand All @@ -55,11 +60,12 @@ class RendezvousServer : public SessionEstablishmentDelegate
Messaging::ExchangeManager * mExchangeManager = nullptr;

PASESession mPairingSession;
uint16_t mNextKeyId = 0;
SecureSessionMgr * mSessionMgr = nullptr;

Transport::AdminPairingInfo * mAdmin = nullptr;

SessionIDAllocator * mIDAllocator = nullptr;

const RendezvousAdvertisementDelegate * mAdvDelegate;

bool HasAdvertisementDelegate() const { return mAdvDelegate != nullptr; }
Expand Down
28 changes: 18 additions & 10 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class ServerStorageDelegate : public PersistentStorageDelegate
};

ServerStorageDelegate gServerStorage;
SessionIDAllocator gSessionIDAllocator;

CHIP_ERROR PersistAdminPairingToKVS(AdminPairingInfo * admin, AdminId nextAvailableId)
{
Expand Down Expand Up @@ -149,7 +150,7 @@ void EraseAllAdminPairingsUpTo(AdminId nextAvailableId)
}
}

static CHIP_ERROR RestoreAllSessionsFromKVS(SecureSessionMgr & sessionMgr, RendezvousServer & server)
static CHIP_ERROR RestoreAllSessionsFromKVS(SecureSessionMgr & sessionMgr)
{
uint16_t nextSessionKeyId = 0;
// It's not an error if the key doesn't exist. Just return right away.
Expand All @@ -170,16 +171,22 @@ static CHIP_ERROR RestoreAllSessionsFromKVS(SecureSessionMgr & sessionMgr, Rende

ChipLogProgress(AppServer, "Fetched the session information: from 0x" ChipLogFormatX64,
ChipLogValueX64(session->PeerConnection().GetPeerNodeId()));
sessionMgr.NewPairing(Optional<Transport::PeerAddress>::Value(session->PeerConnection().GetPeerAddress()),
session->PeerConnection().GetPeerNodeId(), session, SecureSession::SessionRole::kResponder,
connection.GetAdminId(), nullptr);
if (gSessionIDAllocator.Reserve(keyId) == CHIP_NO_ERROR)
{
sessionMgr.NewPairing(Optional<Transport::PeerAddress>::Value(session->PeerConnection().GetPeerAddress()),
session->PeerConnection().GetPeerNodeId(), session, SecureSession::SessionRole::kResponder,
connection.GetAdminId(), nullptr);
}
else
{
ChipLogProgress(AppServer, "Session Key ID %" PRIu16 " cannot be used. Skipping over this session", keyId);
}
session->Clear();
}
}

chip::Platform::Delete(session);

server.SetNextKeyId(nextSessionKeyId);
return CHIP_NO_ERROR;
}

Expand All @@ -189,6 +196,7 @@ void EraseAllSessionsUpTo(uint16_t nextSessionKeyId)

for (uint16_t keyId = 0; keyId < nextSessionKeyId; keyId++)
{
gSessionIDAllocator.Free(keyId);
StorablePeerConnection::DeleteFromKVS(gServerStorage, keyId);
}
}
Expand Down Expand Up @@ -427,9 +435,8 @@ CHIP_ERROR OpenDefaultPairingWindow(ResetAdmins resetAdmins, chip::PairingWindow

if (resetAdmins == ResetAdmins::kYes)
{
uint16_t nextKeyId = gRendezvousServer.GetNextKeyId();
EraseAllAdminPairingsUpTo(gNextAvailableAdminId);
EraseAllSessionsUpTo(nextKeyId);
EraseAllSessionsUpTo(gSessionIDAllocator.Peek());
// Only resetting gNextAvailableAdminId at reboot otherwise previously paired device with adminID 0
// can continue sending messages to accessory as next available admin will also be 0.
// This logic is not up to spec, will be implemented up to spec once AddOptCert is implemented.
Expand Down Expand Up @@ -462,7 +469,7 @@ void InitServer(AppDelegate * delegate)
PersistedStorage::KeyValueStoreMgrImpl().Init("/tmp/chip_server_kvs");
#endif

err = gRendezvousServer.Init(delegate, &gServerStorage);
err = gRendezvousServer.Init(delegate, &gServerStorage, &gSessionIDAllocator);
SuccessOrExit(err);

gAdvDelegate.SetDelegate(delegate);
Expand Down Expand Up @@ -517,7 +524,7 @@ void InitServer(AppDelegate * delegate)
VerifyOrExit(CHIP_NO_ERROR == RestoreAllAdminPairingsFromKVS(gAdminPairings, gNextAvailableAdminId),
ChipLogError(AppServer, "Could not restore admin table"));

VerifyOrExit(CHIP_NO_ERROR == RestoreAllSessionsFromKVS(gSessions, gRendezvousServer),
VerifyOrExit(CHIP_NO_ERROR == RestoreAllSessionsFromKVS(gSessions),
ChipLogError(AppServer, "Could not restore previous sessions"));
}
else
Expand All @@ -542,7 +549,8 @@ void InitServer(AppDelegate * delegate)
err = gExchangeMgr.RegisterUnsolicitedMessageHandlerForProtocol(Protocols::ServiceProvisioning::Id, &gCallbacks);
VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER);

err = gCASEServer.ListenForSessionEstablishment(&gExchangeMgr, &gTransports, &gSessions, &GetGlobalAdminPairingTable());
err = gCASEServer.ListenForSessionEstablishment(&gExchangeMgr, &gTransports, &gSessions, &GetGlobalAdminPairingTable(),
&gSessionIDAllocator);
SuccessOrExit(err);

exit:
Expand Down
Loading