Skip to content

Commit

Permalink
Add support for persisting paired device information on CHIP controll…
Browse files Browse the repository at this point in the history
…er (#3284)

* Add support for persisting paired device information on CHIP controller

* Fix snprintf format error

* Fix Android build issues

* address review comments

* another attempt to fix Android build

* fix Android build

* Fix secure pairing serialize

* Fix mbedTLS based tests

* Reduce stack needed for the test

* Reduce size requirement for SecurePairingSessionSerialized

* Fix stack overflow in tests when ran using QEMU

* Address review comments
  • Loading branch information
pan-apple authored and pull[bot] committed Nov 10, 2020
1 parent 2db7335 commit 9f0963a
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 23 deletions.
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]; \
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 @@ -251,11 +274,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 @@ -270,13 +296,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));

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 @@ -291,7 +338,7 @@ CHIP_ERROR ChipDeviceController::EstablishSecureSession()
return err;
}

CHIP_ERROR ChipDeviceController::ResumeSecureSession()
CHIP_ERROR ChipDeviceController::ResumeSecureSession(NodeId peer)
{
if (mConState == kConnectionState_SecureConnected)
{
Expand All @@ -304,13 +351,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 @@ -377,8 +420,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 @@ -394,7 +437,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 @@ -521,12 +565,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
{
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

0 comments on commit 9f0963a

Please sign in to comment.