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

Add support for persisting paired device information on CHIP controller #3284

Merged
merged 12 commits into from
Oct 20, 2020
96 changes: 79 additions & 17 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

// module header, comes first
#include <controller/CHIPDeviceController.h>

Expand All @@ -46,6 +50,7 @@
#include <support/logging/CHIPLogging.h>

#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
Expand All @@ -58,6 +63,22 @@ namespace DeviceController {

using namespace chip::Encoding;

constexpr const char * kDeviceCredentialsKeyPrefix = "DeviceCredentials";
constexpr const char * kDeviceAddressKeyPrefix = "DeviceAddress";

// This macro generates a key using node ID an key prefix, and performs the given action
// on that key.
#define PERSISTENT_KEY_OP(node, keyPrefix, key, action) \
do \
{ \
const size_t len = strlen(keyPrefix); \
/* 2 * sizeof(NodeId) to accomodate 2 character for each byte in Node Id */ \
char key[len + 2 * sizeof(NodeId) + 1]; \
pan-apple marked this conversation as resolved.
Show resolved Hide resolved
nlSTATIC_ASSERT_PRINT(sizeof(node) <= sizeof(uint64_t), "Node ID size is greater than expected"); \
snprintf(key, sizeof(key), "%s%" PRIx64, keyPrefix, node); \
action; \
} while (0)

ChipDeviceController::ChipDeviceController()
{
mState = kState_NotInitialized;
Expand All @@ -69,6 +90,7 @@ ChipDeviceController::ChipDeviceController()
mOnError = nullptr;
mOnNewConnection = nullptr;
mPairingDelegate = nullptr;
mStorageDelegate = nullptr;
mDeviceAddr = IPAddress::Any;
mDevicePort = CHIP_PORT;
mInterface = INET_NULL_INTERFACEID;
Expand Down Expand Up @@ -117,12 +139,14 @@ CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, System::Layer * system
return err;
}

CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, DevicePairingDelegate * pairingDelegate)
CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, DevicePairingDelegate * pairingDelegate,
PersistentStorageDelegate * storage)
{
CHIP_ERROR err = Init(localNodeId);
SuccessOrExit(err);

mPairingDelegate = pairingDelegate;
mStorageDelegate = storage;

exit:
return err;
Expand Down Expand Up @@ -167,7 +191,6 @@ CHIP_ERROR ChipDeviceController::Shutdown()
memset(&mOnComplete, 0, sizeof(mOnComplete));
mOnError = nullptr;
mOnNewConnection = nullptr;
mMessageNumber = 0;
mRemoteDeviceId.ClearValue();

exit:
Expand Down Expand Up @@ -250,11 +273,14 @@ CHIP_ERROR ChipDeviceController::ConnectDeviceWithoutSecurePairing(NodeId remote
return CHIP_NO_ERROR;
}

CHIP_ERROR ChipDeviceController::EstablishSecureSession()
CHIP_ERROR ChipDeviceController::EstablishSecureSession(NodeId peer)
{
CHIP_ERROR err = CHIP_NO_ERROR;
SecurePairingSession pairing;
SecurePairingSession * pairingSession = mSecurePairingSession;
Inet::IPAddress peerAddr = mDeviceAddr;

if (mState != kState_Initialized || mSessionManager != nullptr || mConState != kConnectionState_Connected)
if (mState != kState_Initialized || mSessionManager != nullptr || mConState == kConnectionState_SecureConnected)
{
ExitNow(err = CHIP_ERROR_INCORRECT_STATE);
}
Expand All @@ -269,13 +295,34 @@ CHIP_ERROR ChipDeviceController::EstablishSecureSession()

mConState = kConnectionState_SecureConnected;

if (mStorageDelegate != nullptr)
{
const char * credentials;
const char * address;

PERSISTENT_KEY_OP(peer, kDeviceCredentialsKeyPrefix, key, credentials = mStorageDelegate->GetKeyValue(key));
PERSISTENT_KEY_OP(peer, kDeviceAddressKeyPrefix, key, address = mStorageDelegate->GetKeyValue(key));

SecurePairingSessionSerialized serialized;

VerifyOrExit(credentials != nullptr, err = CHIP_ERROR_KEY_NOT_FOUND_FROM_PEER);
VerifyOrExit(strlen(credentials) <= sizeof(serialized.inner), err = CHIP_ERROR_INVALID_STRING_LENGTH);
strncpy(Uint8::to_char(serialized.inner), credentials, sizeof(serialized.inner));
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

err = pairing.Deserialize(serialized);
SuccessOrExit(err);

pairingSession = &pairing;

VerifyOrExit(address != nullptr, err = CHIP_ERROR_KEY_NOT_FOUND_FROM_PEER);

VerifyOrExit(IPAddress::FromString(address, peerAddr), err = CHIP_ERROR_INVALID_ADDRESS);
}

err = mSessionManager->NewPairing(
Optional<Transport::PeerAddress>::Value(Transport::PeerAddress::UDP(mDeviceAddr, mDevicePort, mInterface)),
mSecurePairingSession);
Optional<Transport::PeerAddress>::Value(Transport::PeerAddress::UDP(peerAddr, mDevicePort, mInterface)), pairingSession);
SuccessOrExit(err);

mMessageNumber = 1;

exit:

if (err != CHIP_NO_ERROR)
Expand All @@ -290,7 +337,7 @@ CHIP_ERROR ChipDeviceController::EstablishSecureSession()
return err;
}

CHIP_ERROR ChipDeviceController::ResumeSecureSession()
CHIP_ERROR ChipDeviceController::ResumeSecureSession(NodeId peer)
{
if (mConState == kConnectionState_SecureConnected)
{
Expand All @@ -303,13 +350,9 @@ CHIP_ERROR ChipDeviceController::ResumeSecureSession()
mSessionManager = nullptr;
}

uint32_t currentMessageNumber = mMessageNumber;

CHIP_ERROR err = EstablishSecureSession();
CHIP_ERROR err = EstablishSecureSession(peer);
SuccessOrExit(err);

mMessageNumber = currentMessageNumber;

exit:

if (err != CHIP_NO_ERROR)
Expand Down Expand Up @@ -376,8 +419,8 @@ CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer *
if (!IsSecurelyConnected())
{
// For now, it's expected that the device is connected
VerifyOrExit(IsConnected(), err = CHIP_ERROR_INCORRECT_STATE);
err = EstablishSecureSession();
VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE);
err = EstablishSecureSession(mRemoteDeviceId.Value());
SuccessOrExit(err);

trySessionResumption = false;
Expand All @@ -393,7 +436,8 @@ CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer *
// Try sesion resumption if needed
if (err != CHIP_NO_ERROR && trySessionResumption)
{
err = ResumeSecureSession();
VerifyOrExit(mRemoteDeviceId.HasValue(), err = CHIP_ERROR_INCORRECT_STATE);
err = ResumeSecureSession(mRemoteDeviceId.Value());
// If session resumption failed, let's free the extra reference to
// the buffer. If not, SendMessage would free it.
VerifyOrExit(err == CHIP_NO_ERROR, PacketBuffer::Free(buffer));
Expand Down Expand Up @@ -520,12 +564,30 @@ void ChipDeviceController::OnRendezvousStatusUpdate(RendezvousSessionDelegate::S
{
mPairingDelegate->OnNetworkCredentialsRequested(mRendezvousSession);
}

if (mStorageDelegate != nullptr)
{
SecurePairingSessionSerialized serialized;
CHIP_ERROR err = mSecurePairingSession->Serialize(serialized);
if (err == CHIP_NO_ERROR)
{
PERSISTENT_KEY_OP(mSecurePairingSession->GetPeerNodeId(), kDeviceCredentialsKeyPrefix, key,
mStorageDelegate->SetKeyValue(key, Uint8::to_const_char(serialized.inner)));
}
}
break;

case RendezvousSessionDelegate::NetworkProvisioningSuccess:

ChipLogDetail(Controller, "Remote device was assigned an ip address\n");
mDeviceAddr = mRendezvousSession->GetIPAddress();
if (mStorageDelegate != nullptr)
{
char addrStr[INET6_ADDRSTRLEN];
mDeviceAddr.ToString(addrStr, INET6_ADDRSTRLEN);
PERSISTENT_KEY_OP(mRendezvousSession->GetPairingSession().GetPeerNodeId(), kDeviceAddressKeyPrefix, key,
mStorageDelegate->SetKeyValue(key, addrStr));
}
break;

default:
Expand Down
11 changes: 7 additions & 4 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#pragma once

#include <controller/CHIPPersistentStorageDelegate.h>
#include <core/CHIPCore.h>
#include <core/CHIPTLV.h>
#include <support/DLLUtil.h>
Expand Down Expand Up @@ -114,7 +115,8 @@ class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, public
* Init function to be used when already-initialized System::Layer and InetLayer are available.
*/
CHIP_ERROR Init(NodeId localDeviceId, System::Layer * systemLayer, Inet::InetLayer * inetLayer);
CHIP_ERROR Init(NodeId localDeviceId, DevicePairingDelegate * pairingDelegate);
CHIP_ERROR Init(NodeId localDeviceId, DevicePairingDelegate * pairingDelegate,
PersistentStorageDelegate * storageDelegate = nullptr);
CHIP_ERROR Shutdown();

// ----- Connection Management -----
Expand Down Expand Up @@ -257,7 +259,6 @@ class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, public
uint16_t mDevicePort;
Inet::InterfaceId mInterface;
Optional<NodeId> mRemoteDeviceId;
uint32_t mMessageNumber = 0;

SecurePairingSession mPairingSession;
SecurePairingUsingTestSecret * mTestSecurePairingSecret = nullptr;
Expand All @@ -266,11 +267,13 @@ class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, public

DevicePairingDelegate * mPairingDelegate;

PersistentStorageDelegate * mStorageDelegate;

void ClearRequestState();
void ClearOpState();

CHIP_ERROR EstablishSecureSession();
CHIP_ERROR ResumeSecureSession();
CHIP_ERROR EstablishSecureSession(NodeId peer);
CHIP_ERROR ResumeSecureSession(NodeId peer);
};

} // namespace DeviceController
Expand Down
64 changes: 64 additions & 0 deletions src/controller/CHIPPersistentStorageDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
*
* Copyright (c) 2020 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 <core/CHIPCore.h>
#include <support/DLLUtil.h>

namespace chip {
namespace DeviceController {

class DLL_EXPORT PersistentStorageDelegate
mspang marked this conversation as resolved.
Show resolved Hide resolved
{
public:
virtual ~PersistentStorageDelegate() {}

/**
* @brief
* Lookup the key and return it's stringified value
*
* @param[in] key Key to lookup
* @return Value or nullptr if not found. Lifetime of the returned
* buffer is tied to the delegate object. If the delegate is
* freed, the returned value would be inaccessible.
*/
virtual const char * GetKeyValue(const char * key) = 0;

/**
* @brief
* Set the value for the key
*
* @param[in] key Key to be set
* @param[in] value Value to be set
* @return returns corresponding error if unsuccessful
*/
virtual CHIP_ERROR SetKeyValue(const char * key, const char * value) = 0;

/**
* @brief
* Deletes the value for the key
*
* @param[in] key Key to be deleted
* @return returns corresponding error if unsuccessful
*/
virtual CHIP_ERROR DeleteKeyValue(const char * key) = 0;
};

} // namespace DeviceController
} // namespace chip
Loading