blob: b0d2100bedd33bbcb60f83a96a773e8b883f0a72 [file] [log] [blame]
/*
*
* Copyright (c) 2016-2017 Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file implements application keys trait data sink interfaces.
*
*/
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/MathUtils.h>
#include <Weave/Support/crypto/WeaveCrypto.h>
#include "ApplicationKeysTraitDataSink.h"
namespace Schema {
namespace Weave {
namespace Trait {
namespace Auth {
namespace ApplicationKeysTrait {
using namespace nl::Weave;
using namespace nl::Weave::TLV;
using namespace nl::Weave::Crypto;
using namespace nl::Weave::Profiles::DataManagement;
using namespace nl::Weave::Profiles::Security::AppKeys;
/**
* The constructor method.
*/
ApplicationKeysTraitDataSink::ApplicationKeysTraitDataSink(void)
: TraitDataSink(&ApplicationKeysTrait::TraitSchema)
{
GroupKeyStore = NULL;
}
/**
* This method sets the platform specific key store object.
*
* @param[in] groupKeyStore Pointer to the platform group key store object. It can be
* NULL if no key store object is required.
* @retval None.
*
*/
void ApplicationKeysTraitDataSink::SetGroupKeyStore(GroupKeyStoreBase *groupKeyStore)
{
GroupKeyStore = groupKeyStore;
}
/**
* This method is invoked to signal the occurrence of an event.
*
* @param[in] aType Event type.
*
* @retval #WEAVE_NO_ERROR.
*
*/
WEAVE_ERROR ApplicationKeysTraitDataSink::OnEvent(uint16_t aType, void *aInEventParam)
{
WeaveLogDetail(DataManagement, "ApplicationKeysTraitDataSink::OnEvent event: %u", aType);
return WEAVE_NO_ERROR;
}
/**
* This method reads in the data associated with the specified leaf handle.
*
* @param[in] aLeafHandle Path handle to a leaf node.
* @param[in] aReader A reference to the TLVReader object that contains leaf data.
*
* @retval #WEAVE_NO_ERROR On success.
* @retval #WEAVE_ERROR_INVALID_ARGUMENT
* If no pointer to the GroupKeyStore was set or if value of
* one of the decoded TLV parameters has invalid value.
* @retval #WEAVE_ERROR_INVALID_TLV_TAG
* If input property path handle (aLeafHandle) has invalid value.
* @retval #WEAVE_ERROR_WRONG_TLV_TYPE
* If input TLV data has wrong type.
* @retval other Error returned by TLV reader.
*
*/
WEAVE_ERROR ApplicationKeysTraitDataSink::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader &aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint32_t keyType;
uint8_t keyCount;
uint8_t maxKeyCount;
WeaveGroupKey groupKey;
if (ApplicationKeysTrait::kPropertyHandle_EpochKeys == aLeafHandle)
{
keyType = WeaveKeyId::kType_AppEpochKey;
maxKeyCount = WEAVE_CONFIG_MAX_APPLICATION_EPOCH_KEYS;
}
else if (ApplicationKeysTrait::kPropertyHandle_MasterKeys == aLeafHandle)
{
keyType = WeaveKeyId::kType_AppGroupMasterKey;
maxKeyCount = WEAVE_CONFIG_MAX_APPLICATION_GROUPS;
}
else
{
WeaveLogDetail(DataManagement, "<< UNKNOWN!");
ExitNow(err = WEAVE_ERROR_INVALID_TLV_TAG);
}
VerifyOrExit(GroupKeyStore != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
{
TLVType OuterContainerType;
keyCount = 0;
VerifyOrExit(aReader.GetType() == kTLVType_Array, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = aReader.EnterContainer(OuterContainerType);
SuccessOrExit(err);
// Delete all group keys of the specified type from the group key store.
GroupKeyStore->DeleteGroupKeysOfAType(keyType);
while ((err = aReader.Next(kTLVType_Structure, AnonymousTag)) == WEAVE_NO_ERROR)
{
TLVType containerType2;
if (keyCount == maxKeyCount)
{
WeaveLogDetail(DataManagement, "Cannot handle more than %d %s, skip",
maxKeyCount, (keyType == WeaveKeyId::kType_AppEpochKey) ? "epoch keys" : "application groups");
break;
}
err = aReader.EnterContainer(containerType2);
SuccessOrExit(err);
if (ApplicationKeysTrait::kPropertyHandle_EpochKeys == aLeafHandle)
{
int64_t startTimeMSec;
uint64_t tlvTag;
nl::Weave::TLV::TLVType tlvType;
uint8_t epochKeyNumber;
err = aReader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_EpochKey_KeyId));
SuccessOrExit(err);
err = aReader.Get(epochKeyNumber);
SuccessOrExit(err);
groupKey.KeyId = WeaveKeyId::MakeEpochKeyId(epochKeyNumber);
err = aReader.Next();
SuccessOrExit(err);
tlvTag = aReader.GetTag();
VerifyOrExit(tlvTag == ContextTag(kTag_EpochKey_StartTime), err = WEAVE_ERROR_INVALID_TLV_TAG);
tlvType = aReader.GetType();
VerifyOrExit(tlvType == kTLVType_SignedInteger ||
tlvType == kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = aReader.Get(startTimeMSec);
SuccessOrExit(err);
// Verify that the time value is in the expected range (in milliseconds).
VerifyOrExit(startTimeMSec >= 0 && startTimeMSec <= (static_cast<int64_t>(UINT32_MAX) * 1000),
err = WEAVE_ERROR_INVALID_ARGUMENT);
// Convert UTC time value with msec precision to seconds (rounded up).
groupKey.StartTime = nl::Weave::Platform::DivideBy1000(startTimeMSec + 999);
err = aReader.Next(kTLVType_ByteString, ContextTag(kTag_EpochKey_Key));
}
else
{
uint8_t appGroupLocalNumber;
err = aReader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_ApplicationGroup_GlobalId));
SuccessOrExit(err);
err = aReader.Get(groupKey.GlobalId);
SuccessOrExit(err);
err = aReader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_ApplicationGroup_ShortId));
SuccessOrExit(err);
err = aReader.Get(appGroupLocalNumber);
SuccessOrExit(err);
groupKey.KeyId = WeaveKeyId::MakeAppGroupMasterKeyId(appGroupLocalNumber);
err = aReader.Next(kTLVType_ByteString, ContextTag(kTag_ApplicationGroup_Key));
}
SuccessOrExit(err);
groupKey.KeyLen = aReader.GetLength();
VerifyOrExit(groupKey.KeyLen <= sizeof(groupKey.Key), err = WEAVE_ERROR_INVALID_ARGUMENT);
err = aReader.GetBytes(groupKey.Key, groupKey.KeyLen);
SuccessOrExit(err);
err = GroupKeyStore->StoreGroupKey(groupKey);
SuccessOrExit(err);
WeaveLogDetail(DataManagement, "<< groupKeyId = %08X", groupKey.KeyId);
keyCount++;
err = aReader.ExitContainer(containerType2);
SuccessOrExit(err);
}
// Note that ExitContainer() internally skips all unread elements till the end of current container.
err = aReader.ExitContainer(OuterContainerType);
SuccessOrExit(err);
}
exit:
ClearSecretData(groupKey.Key, sizeof(groupKey.Key));
return err;
}
} // ApplicationKeysTrait
} // Auth
} // Trait
} // Weave
} // Schema