Skip to content

Commit

Permalink
Add support for persisting paired device information on CHIP controller
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-apple committed Oct 16, 2020
1 parent 17924c7 commit d2295a1
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 21 deletions.
88 changes: 71 additions & 17 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ namespace DeviceController {

using namespace chip::Encoding;

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

// This macro generats 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); \
char key[len + sizeof(NodeId) + 1]; \
snprintf(key, sizeof(key), "%s%llx", keyPrefix, node); \
action; \
} while (0)

ChipDeviceController::ChipDeviceController()
{
mState = kState_NotInitialized;
Expand All @@ -69,6 +83,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 +132,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 +184,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 +266,14 @@ CHIP_ERROR ChipDeviceController::ConnectDeviceWithoutSecurePairing(NodeId remote
return CHIP_NO_ERROR;
}

CHIP_ERROR ChipDeviceController::EstablishSecureSession()
CHIP_ERROR ChipDeviceController::EstablishSecureSession(const 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 +288,33 @@ 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);
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 @@ -290,7 +329,7 @@ CHIP_ERROR ChipDeviceController::EstablishSecureSession()
return err;
}

CHIP_ERROR ChipDeviceController::ResumeSecureSession()
CHIP_ERROR ChipDeviceController::ResumeSecureSession(const NodeId & peer)
{
if (mConState == kConnectionState_SecureConnected)
{
Expand All @@ -303,13 +342,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 +411,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 +428,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 +556,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
42 changes: 38 additions & 4 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,38 @@ typedef void (*ErrorHandler)(ChipDeviceController * deviceController, void * app
const Inet::IPPacketInfo * pktInfo);
typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload);

class DLL_EXPORT PersistentStorageDelegate
{
public:
/**
* @brief
* Lookup the key and return it's stringified value
*
* @param[in] key Key to lookup
* @return Value or nullptr if not found
*/
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;
};

class DLL_EXPORT DevicePairingDelegate
{
public:
Expand Down Expand Up @@ -114,7 +146,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 +290,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 +298,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(const NodeId & peer);
CHIP_ERROR ResumeSecureSession(const NodeId & peer);
};

} // namespace DeviceController
Expand Down
83 changes: 83 additions & 0 deletions src/transport/SecurePairingSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
*
*/

#include <inttypes.h>

#include <core/CHIPSafeCasts.h>
#include <protocols/CHIPProtocols.h>
#include <support/BufBound.h>
Expand Down Expand Up @@ -56,6 +58,87 @@ SecurePairingSession::~SecurePairingSession()
memset(&mKe[0], 0, sizeof(mKe));
}

typedef struct
{
uint16_t mKeLen;
uint8_t mKe[kMAX_Hash_Length];
uint8_t mPairingComplete;
uint64_t mLocalNodeId;
uint64_t mPeerNodeId;
uint16_t mLocalKeyId;
uint16_t mPeerKeyId;
uint64_t padding;
} SecurePairingSessionSerializable;

CHIP_ERROR SecurePairingSession::Serialize(SecurePairingSessionSerialized & output)
{
CHIP_ERROR error = CHIP_NO_ERROR;

const NodeId localNodeId = (mLocalNodeId.HasValue()) ? mLocalNodeId.Value() : kUndefinedNodeId;
const NodeId peerNodeId = (mPeerNodeId.HasValue()) ? mPeerNodeId.Value() : kUndefinedNodeId;
VerifyOrExit(CanCastTo<uint16_t>(mKeLen), error = CHIP_ERROR_INTERNAL);
VerifyOrExit(CanCastTo<uint64_t>(localNodeId), error = CHIP_ERROR_INTERNAL);
VerifyOrExit(CanCastTo<uint64_t>(peerNodeId), error = CHIP_ERROR_INTERNAL);
VerifyOrExit(CanCastTo<uint16_t>(sizeof(SecurePairingSessionSerializable)), error = CHIP_ERROR_INTERNAL);

{
uint8_t paired = (mPairingComplete) ? 1 : 0;
uint16_t keLen = static_cast<uint16_t>(mKeLen);
uint16_t serializedLen = 0;
SecurePairingSessionSerializable serializable = {
keLen, { 0 }, paired, localNodeId, peerNodeId, mLocalKeyId, mPeerKeyId, 0
};
memcpy(serializable.mKe, mKe, kMAX_Hash_Length);

VerifyOrExit(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT);

serializedLen = chip::Base64Encode(Uint8::to_const_uchar((uint8_t *) &serializable),
static_cast<uint16_t>(sizeof(serializable)), Uint8::to_char(output.inner));
VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT);
output.inner[serializedLen] = '\0';
}

exit:
return error;
}

CHIP_ERROR SecurePairingSession::Deserialize(SecurePairingSessionSerialized & input)
{
CHIP_ERROR error = CHIP_NO_ERROR;
SecurePairingSessionSerializable serializable;
size_t maxlen = BASE64_ENCODED_LEN(sizeof(serializable));
size_t len = strnlen(Uint8::to_char(input.inner), maxlen);
uint16_t deserializedLen = 0;

VerifyOrExit(BASE64_MAX_DECODED_LEN(len) <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(CanCastTo<uint16_t>(len), error = 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));
VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT);

mPairingComplete = (serializable.mPairingComplete == 1);

VerifyOrExit(CanCastTo<uint16_t>(serializable.mKeLen), error = CHIP_ERROR_INTERNAL);
mKeLen = static_cast<size_t>(serializable.mKeLen);

VerifyOrExit(mKeLen <= sizeof(mKe), error = CHIP_ERROR_INVALID_ARGUMENT);
memset(mKe, 0, sizeof(mKe));
memcpy(mKe, serializable.mKe, mKeLen);

mLocalNodeId = Optional<NodeId>::Value(serializable.mLocalNodeId);
mPeerNodeId = Optional<NodeId>::Value(serializable.mPeerNodeId);

mLocalKeyId = serializable.mLocalKeyId;
mPeerKeyId = serializable.mPeerKeyId;

exit:
return error;
}

CHIP_ERROR SecurePairingSession::Init(uint32_t setupCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate)
{
Expand Down
20 changes: 20 additions & 0 deletions src/transport/SecurePairingSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <core/ReferenceCounted.h>
#include <crypto/CHIPCryptoPAL.h>
#include <support/Base64.h>
#include <system/SystemPacketBuffer.h>
#include <transport/SecureSession.h>

Expand Down Expand Up @@ -67,6 +68,8 @@ class DLL_EXPORT SecurePairingSessionDelegate : public ReferenceCounted<SecurePa
~SecurePairingSessionDelegate() override {}
};

struct SecurePairingSessionSerialized;

class DLL_EXPORT SecurePairingSession
{
public:
Expand Down Expand Up @@ -159,6 +162,18 @@ class DLL_EXPORT SecurePairingSession
*/
uint16_t GetLocalKeyId() { return mLocalKeyId; }

/** @brief Serialize the Pairing Session to a string.
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR Serialize(SecurePairingSessionSerialized & output);

/** @brief Deserialize the Pairing Session from the string.
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR Deserialize(SecurePairingSessionSerialized & input);

private:
CHIP_ERROR Init(uint32_t setupCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen, Optional<NodeId> myNodeId,
uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
Expand Down Expand Up @@ -248,4 +263,9 @@ class SecurePairingUsingTestSecret : public SecurePairingSession
CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, System::PacketBuffer * msg) override { return CHIP_NO_ERROR; }
};

typedef struct SecurePairingSessionSerialized
{
uint8_t inner[BASE64_ENCODED_LEN(sizeof(SecurePairingSession))];
} SecurePairingSessionSerialized;

} // namespace chip
Loading

0 comments on commit d2295a1

Please sign in to comment.