diff --git a/BUILD.gn b/BUILD.gn index 8965697194c1be..ff0f86c3476726 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -40,6 +40,7 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") { "${chip_root}/src/inet", "${chip_root}/src/lib", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/message", "${chip_root}/src/lib/shell", "${chip_root}/src/lib/support", "${chip_root}/src/lwip:all", diff --git a/src/include/platform/CHIPDeviceLayer.h b/src/include/platform/CHIPDeviceLayer.h index b8adde2fa956de..16ec501d645db0 100644 --- a/src/include/platform/CHIPDeviceLayer.h +++ b/src/include/platform/CHIPDeviceLayer.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,11 @@ namespace chip { namespace DeviceLayer { struct ChipDeviceEvent; + +using chip::ExchangeMgr; +using chip::FabricState; +using chip::MessageLayer; + extern chip::System::Layer SystemLayer; extern Inet::InetLayer InetLayer; diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.ipp b/src/include/platform/internal/GenericPlatformManagerImpl.ipp index 9b5d03c6912c5a..6e399f8ff0321e 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.ipp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.ipp @@ -61,7 +61,7 @@ CHIP_ERROR GenericPlatformManagerImpl::_InitChipStack(void) } SuccessOrExit(err); - // Initialize the CHIP system layer. + // Initialize the CHIP System Layer. new (&SystemLayer) System::Layer(); err = SystemLayer.Init(NULL); if (err != CHIP_SYSTEM_NO_ERROR) @@ -70,7 +70,7 @@ CHIP_ERROR GenericPlatformManagerImpl::_InitChipStack(void) } SuccessOrExit(err); - // Initialize the CHIP Inet layer. + // Initialize the CHIP Inet Layer. new (&InetLayer) Inet::InetLayer(); err = InetLayer.Init(SystemLayer, NULL); if (err != INET_NO_ERROR) @@ -79,9 +79,47 @@ CHIP_ERROR GenericPlatformManagerImpl::_InitChipStack(void) } SuccessOrExit(err); - // TODO Perform dynamic configuration of the core CHIP objects based on stored settings. +#if CHIP_ENABLE_MESSAGE_LAYER + // Initialize the CHIP Fabric State object. + new (&FabricState) ChipFabricState(); + err = FabricState.Init(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "FabricState initialization failed: %s", ErrorStr(err)); + } + SuccessOrExit(err); + + FabricState.DefaultSubnet = kChipSubnetId_PrimaryWiFi; + + { + ChipMessageLayer::InitContext initContext; + initContext.systemLayer = &SystemLayer; + initContext.inet = &InetLayer; + initContext.listenTCP = true; + initContext.listenUDP = true; + initContext.fabricState = &FabricState; + + // Initialize the CHIP Message Layer. + new (&MessageLayer) ChipMessageLayer(); + err = MessageLayer.Init(&initContext); + if (err != CHIP_NO_ERROR) { + ChipLogError(DeviceLayer, "MessageLayer initialization failed: %s", ErrorStr(err)); + } + SuccessOrExit(err); + } + + // Hook the MessageLayer activity changed callback. + MessageLayer.SetSignalMessageLayerActivityChanged(ImplClass::HandleMessageLayerActivityChanged); + + // Initialize the CHIP Exchange Manager. + err = ExchangeMgr.Init(&MessageLayer); + if (err != CHIP_NO_ERROR) { + ChipLogError(DeviceLayer, "ExchangeMgr initialization failed: %s", ErrorStr(err)); + } + SuccessOrExit(err); +#endif - // Initialize the CHIP BLE manager. + // Initialize the CHIP BLE Manager. #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE err = BLEMgr().Init(); if (err != CHIP_NO_ERROR) diff --git a/src/lib/BUILD.gn b/src/lib/BUILD.gn index 4be170cf6d1955..19040351634e6f 100644 --- a/src/lib/BUILD.gn +++ b/src/lib/BUILD.gn @@ -26,6 +26,8 @@ static_library("lib") { "${chip_root}/src/crypto", "${chip_root}/src/inet", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/message", + "${chip_root}/src/lib/protocols", "${chip_root}/src/lib/support", "${chip_root}/src/platform", "${chip_root}/src/setup_payload", diff --git a/src/lib/message/BUILD.gn b/src/lib/message/BUILD.gn index f94b6859a50d64..f3752b804a7414 100644 --- a/src/lib/message/BUILD.gn +++ b/src/lib/message/BUILD.gn @@ -43,6 +43,14 @@ static_library("message") { "CHIPServerBase.cpp", "CHIPServerBase.h", "ExchangeContext.cpp", + "support/crypto/AESBlockCipher.cpp", + "support/crypto/AESBlockCipher.h", + "support/crypto/CHIPCrypto.cpp", + "support/crypto/CHIPCrypto.h", + "support/crypto/CHIPRNG.cpp", + "support/crypto/CHIPRNG.h", + "support/crypto/CTRMode.cpp", + "support/crypto/CTRMode.h", ] public_deps = [ @@ -51,13 +59,14 @@ static_library("message") { "${chip_root}/src/crypto", "${chip_root}/src/inet", "${chip_root}/src/inet:inet_config_header", - "${chip_root}/src/lib/core", "${chip_root}/src/lib/core:chip_config_header", + "${chip_root}/src/lib/protocols", "${chip_root}/src/lib/support", - "${chip_root}/src/platform", "${chip_root}/src/system", "${nlio_root}:nlio", ] + allow_circular_includes_from = [ "${chip_root}/src/lib/protocols" ] + public_configs = [ ":includes" ] } diff --git a/src/lib/message/support/crypto/AESBlockCipher.cpp b/src/lib/message/support/crypto/AESBlockCipher.cpp new file mode 100644 index 00000000000000..187947cf691a69 --- /dev/null +++ b/src/lib/message/support/crypto/AESBlockCipher.cpp @@ -0,0 +1,112 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 AES block cipher functions for the Weave layer. + * The implementation is based on the OpenSSL library functions. + * This implementation is used when #CHIP_CONFIG_AES_IMPLEMENTATION_OPENSSL + * is enabled (1). + * + */ + +#include + +#include "AESBlockCipher.h" +#include "CHIPCrypto.h" + +namespace chip { +namespace Platform { +namespace Security { + +using namespace chip::Crypto; + +AES128BlockCipher::AES128BlockCipher() +{ + memset(&mKey, 0, sizeof(mKey)); +} + +AES128BlockCipher::~AES128BlockCipher() +{ + Reset(); +} + +void AES128BlockCipher::Reset() +{ + ClearSecretData((uint8_t *) &mKey, sizeof(mKey)); +} + +void AES128BlockCipherEnc::SetKey(const uint8_t * key) +{ + // AES_set_encrypt_key(key, kKeyLengthBits, &mKey); +} + +void AES128BlockCipherEnc::EncryptBlock(const uint8_t * inBlock, uint8_t * outBlock) +{ + // AES_encrypt(inBlock, outBlock, &mKey); +} + +void AES128BlockCipherDec::SetKey(const uint8_t * key) +{ + // AES_set_decrypt_key(key, kKeyLengthBits, &mKey); +} + +void AES128BlockCipherDec::DecryptBlock(const uint8_t * inBlock, uint8_t * outBlock) +{ + // AES_decrypt(inBlock, outBlock, &mKey); +} + +AES256BlockCipher::AES256BlockCipher() +{ + memset(&mKey, 0, sizeof(mKey)); +} + +AES256BlockCipher::~AES256BlockCipher() +{ + Reset(); +} + +void AES256BlockCipher::Reset() +{ + ClearSecretData((uint8_t *) &mKey, sizeof(mKey)); +} + +void AES256BlockCipherEnc::SetKey(const uint8_t * key) +{ + // AES_set_encrypt_key(key, kKeyLengthBits, &mKey); +} + +void AES256BlockCipherEnc::EncryptBlock(const uint8_t * inBlock, uint8_t * outBlock) +{ + // AES_encrypt(inBlock, outBlock, &mKey); +} + +void AES256BlockCipherDec::SetKey(const uint8_t * key) +{ + // AES_set_decrypt_key(key, kKeyLengthBits, &mKey); +} + +void AES256BlockCipherDec::DecryptBlock(const uint8_t * inBlock, uint8_t * outBlock) +{ + // AES_decrypt(inBlock, outBlock, &mKey); +} + +} // namespace Security +} // namespace Platform +} // namespace chip diff --git a/src/lib/message/support/crypto/AESBlockCipher.h b/src/lib/message/support/crypto/AESBlockCipher.h index 5c6452e7ee6c4a..917af562307bb3 100644 --- a/src/lib/message/support/crypto/AESBlockCipher.h +++ b/src/lib/message/support/crypto/AESBlockCipher.h @@ -79,19 +79,7 @@ class AES128BlockCipher AES128BlockCipher(void); ~AES128BlockCipher(void); -#if CHIP_CRYPTO_OPENSSL - AES_KEY mKey; -#elif CHIP_CONFIG_AES_IMPLEMENTATION_AESNI - __m128i mKey[kRoundCount + 1]; -#elif CHIP_CRYPTO_MBEDTLS - mbedtls_aes_context mCtx; -#elif CHIP_CONFIG_AES_USE_EXPANDED_KEY - uint8_t mKey[kBlockLength * (kRoundCount + 1)]; -#elif defined(CHIP_AES_128_CTX_PLATFORM) - CHIP_AES_128_CTX_PLATFORM mCtx; -#else uint8_t mKey[kKeyLength]; -#endif }; class DLL_EXPORT AES128BlockCipherEnc : public AES128BlockCipher @@ -125,19 +113,7 @@ class AES256BlockCipher AES256BlockCipher(void); ~AES256BlockCipher(void); -#if CHIP_CONFIG_AES_IMPLEMENTATION_OPENSSL - AES_KEY mKey; -#elif CHIP_CONFIG_AES_IMPLEMENTATION_AESNI - __m128i mKey[kRoundCount + 1]; -#elif CHIP_CRYPTO_MBEDTLS - mbedtls_aes_context mCtx; -#elif CHIP_CONFIG_AES_USE_EXPANDED_KEY - uint8_t mKey[kBlockLength * (kRoundCount + 1)]; -#elif defined(CHIP_AES_256_CTX_PLATFORM) - CHIP_AES_256_CTX_PLATFORM mCtx; -#else uint8_t mKey[kKeyLength]; -#endif }; class DLL_EXPORT AES256BlockCipherEnc : public AES256BlockCipher diff --git a/src/lib/message/support/crypto/CHIPCrypto.cpp b/src/lib/message/support/crypto/CHIPCrypto.cpp new file mode 100644 index 00000000000000..7bc2c513e4ac7d --- /dev/null +++ b/src/lib/message/support/crypto/CHIPCrypto.cpp @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 general purpose cryptographic functions for the Message layer. + * + */ + +#include + +#include "CHIPCrypto.h" + +namespace chip { +namespace Crypto { + +/** + * Compares the first `len` bytes of memory area `buf1` and memory area `buf2`. + * + * The time taken by this function is independent of the data in memory areas `buf1` and `buf2`. + * + * @param[in] buf1 Pointer to a memory block. + * + * @param[in] buf2 Pointer to a memory block. + * + * @param[in] len Size of memory area to compare in bytes. + * + * @retval true if first \c len bytes of memory area \c buf1 and \c buf2 are equal. + * @retval false otherwise. + * + */ +bool ConstantTimeCompare(const uint8_t * buf1, const uint8_t * buf2, uint16_t len) +{ + uint8_t c = 0; + for (uint16_t i = 0; i < len; i++) + c |= buf1[i] ^ buf2[i]; + return c == 0; +} + +} // namespace Crypto +} // namespace chip diff --git a/src/lib/message/support/crypto/CHIPRNG.cpp b/src/lib/message/support/crypto/CHIPRNG.cpp new file mode 100644 index 00000000000000..032ad1ac851f57 --- /dev/null +++ b/src/lib/message/support/crypto/CHIPRNG.cpp @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 secure random data initialization and generation functions + * for the Weave layer. The implementation is based on the OpenSSL Library functions. + * This implementation is used when #WEAVE_CONFIG_RNG_IMPLEMENTATION_OPENSSL + * is enabled (1). + * + */ + +#include "CHIPRNG.h" + +namespace chip { +namespace Platform { +namespace Security { + +CHIP_ERROR InitSecureRandomDataSource(chip::Crypto::EntropyFunct entropyFunct, uint16_t entropyLen, + const uint8_t * personalizationData, uint16_t perDataLen) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR GetSecureRandomData(uint8_t * buf, uint16_t len) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +} // namespace Security +} // namespace Platform +} // namespace chip diff --git a/src/lib/message/support/crypto/CTRMode.cpp b/src/lib/message/support/crypto/CTRMode.cpp new file mode 100644 index 00000000000000..c52f0d534fca17 --- /dev/null +++ b/src/lib/message/support/crypto/CTRMode.cpp @@ -0,0 +1,143 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 a template object for doing counter (CTR) + * mode block ciphers and specialized objects for CTR mode + * AES-128 and AES-256. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#include +#include + +#include "CTRMode.h" + +namespace chip { +namespace Crypto { + +template +CTRMode::CTRMode() +{} + +template +CTRMode::~CTRMode() +{ + Reset(); +} + +template +void CTRMode::SetKey(const uint8_t * key) +{ + mBlockCipher.SetKey(key); +} + +template +void CTRMode::SetCounter(const uint8_t * counter) +{ + memcpy(Counter, counter, kCounterLength); +} + +template +void CTRMode::SetChipMessageCounter(uint64_t sendingNodeId, uint32_t msgId) +{ + // Initialize the CTR-mode encryption counter for encrypting/decrypting a CHIP message. In this mode + // the counter consists of a 128-bit big-endian number with the following format: + // + // (64-bits) | (32 bits) | (32 bits) + // | | + // + Counter[0] = (uint8_t)(sendingNodeId >> (7 * 8)); + Counter[1] = (uint8_t)(sendingNodeId >> (6 * 8)); + Counter[2] = (uint8_t)(sendingNodeId >> (5 * 8)); + Counter[3] = (uint8_t)(sendingNodeId >> (4 * 8)); + Counter[4] = (uint8_t)(sendingNodeId >> (3 * 8)); + Counter[5] = (uint8_t)(sendingNodeId >> (2 * 8)); + Counter[6] = (uint8_t)(sendingNodeId >> (1 * 8)); + Counter[7] = (uint8_t)(sendingNodeId); + Counter[8] = (uint8_t)(msgId >> (3 * 8)); + Counter[9] = (uint8_t)(msgId >> (2 * 8)); + Counter[10] = (uint8_t)(msgId >> (1 * 8)); + Counter[11] = (uint8_t)(msgId); + Counter[12] = 0; + Counter[13] = 0; + Counter[14] = 0; + Counter[15] = 0; +} + +template +void CTRMode::EncryptData(const uint8_t * inData, uint16_t dataLen, uint8_t * outData) +{ + // Index to next byte of encrypted counter to be used. + uint32_t encryptedCounterIndex = mMsgIndex % kCounterLength; + + // For each byte of input data... + for (uint16_t dataIndex = 0; dataIndex < dataLen && mMsgIndex < UINT32_MAX; dataIndex++, mMsgIndex++) + { + // If we need more encrypted counter bytes... + if (encryptedCounterIndex == 0) + { + // Encrypt the next counter value. + mBlockCipher.EncryptBlock(Counter, mEncryptedCounter); + + // Bump the counter. Since the message size is at most UINT32_MAX (and the counter counts blocks) + // we will never need to update more than the four least-significant bytes. + Counter[kCounterLength - 1]++; + if (Counter[kCounterLength - 1] == 0) + { + Counter[kCounterLength - 2]++; + if (Counter[kCounterLength - 2] == 0) + { + Counter[kCounterLength - 3]++; + if (Counter[kCounterLength - 3] == 0) + { + Counter[kCounterLength - 4]++; + } + } + } + } + + // XOR the data with the corresponding byte of the encrypted counter. + outData[dataIndex] = inData[dataIndex] ^ mEncryptedCounter[encryptedCounterIndex]; + + // Bump the counter index. + encryptedCounterIndex++; + if (encryptedCounterIndex == kCounterLength) + encryptedCounterIndex = 0; + } +} + +template +void CTRMode::Reset() +{ + mBlockCipher.Reset(); + mMsgIndex = 0; + memset(Counter, 0, sizeof(Counter)); + ClearSecretData(mEncryptedCounter, sizeof(mEncryptedCounter)); +} + +template class CTRMode; +template class CTRMode; + +} /* namespace Crypto */ +} /* namespace chip */ diff --git a/src/lib/protocols/BUILD.gn b/src/lib/protocols/BUILD.gn new file mode 100644 index 00000000000000..a84cea387f7e2c --- /dev/null +++ b/src/lib/protocols/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2020 Project CHIP Authors +# +# 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. + +import("//build_overrides/chip.gni") +import("//build_overrides/nlio.gni") + +import("${chip_root}/gn/chip/tests.gni") +import("${chip_root}/src/inet/inet.gni") + +config("includes") { + include_dirs = [ "." ] +} + +static_library("protocols") { + output_name = "libChipProtocols" + + sources = [ + "CHIPServerBase.cpp", + "CHIPServerBase.h", + "common/CHIPMessage.cpp", + "common/CHIPMessage.h", + "common/RetainedPacketBuffer.cpp", + "security/CHIPApplicationKeys.cpp", + "security/CHIPApplicationKeys.h", + "security/CHIPDummyGroupKeyStore.cpp", + "security/CHIPDummyGroupKeyStore.h", + "status-report/StatusReportProtocol.cpp", + "status-report/StatusReportProtocol.h", + ] + + public_deps = [ "${chip_root}/src/lib/core" ] + + public_configs = [ ":includes" ] +} diff --git a/src/lib/protocols/CHIPServerBase.cpp b/src/lib/protocols/CHIPServerBase.cpp new file mode 100644 index 00000000000000..a130cda0c784b8 --- /dev/null +++ b/src/lib/protocols/CHIPServerBase.cpp @@ -0,0 +1,239 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 a common, non-instantiatable base object + * for implementing CHIP protocol unsolicited responders + * (i.e. servers) that encapsulates validating authenticated + * requests and sending status reports and also provides common + * data member storage for fabric state and an exchange manager. + * + */ + +#include "CHIPServerBase.h" +#include "CHIPProtocols.h" + +#include +#include +#include +#include +#include + +namespace chip { +namespace Protocols { + +using namespace chip::Encoding; +using namespace chip::TLV; + +/** + * Determine whether an incoming request message to a CHIP server should be accepted or discarded. + * + * This method is intended to be used by CHIP server implementations to implement extensible access control + * policy for incoming request messages. Server implementations that rely on delegate objects should call + * this method early in message processing to determine whether message processing should continue. + * + * This method calls the virtual ChipServerDelegateBase::EnforceAccessControl() method on the supplied delegate to evaluate access + * control policy for the message. CHIP server delegate classes, and application-specific delegates derived + * from the standard server classes, should override the virtual method to enforce specific access control + * policies. + * + * @param[in] ec The ExchangeContext over which the message was received. + * @param[in] msgProfileId The profile id of the received message. + * @param[in] msgType The message type of the received message. + * @param[in] msgInfo A ChipMessageInfo structure containing information about the received message. + * @param[in] delegate The delegate object supplied by the application that can be used to override + * the default message access control policy. + * + * @retval true If the message should be accepted and processed as normal. + * @retval false If message processing should stop and the message the should be discarded. + */ +bool ChipServerBase::EnforceAccessControl(ExchangeContext * ec, uint32_t msgProfileId, uint8_t msgType, + const ChipMessageInfo * msgInfo, ChipServerDelegateBase * delegate) +{ + // Reject all messages if the application hasn't specified a delegate object. + if (delegate == NULL) + { + ChipServerBase::SendStatusReport(ec, kChipProtocol_Common, Common::kStatus_InternalError, CHIP_NO_ERROR); + return false; + } + + // Invoke the virtual method to evaluate the message and decide whether or not to accept it. + ChipServerDelegateBase::AccessControlResult res = ChipServerDelegateBase::kAccessControlResult_NotDetermined; + delegate->EnforceAccessControl(ec, msgProfileId, msgType, msgInfo, res); + + // If the final determination was that the message should be accepted AND the delegate called all the way up to + // the base method, then tell the caller that the message should be accepted. + if (res == ChipServerDelegateBase::kAccessControlResult_FinalAccepted) + { + return true; + } + + // Otherwise the message should not be accepted... + else + { + // Clear the 'Final' bit so that the following checks ignore it. + res &= ~ChipServerDelegateBase::kAccessControlResult_IsFinal; + + // Send a standard response to the requester unless the delegate has already sent a response, or determined + // that no response should be sent. + if (res != ChipServerDelegateBase::kAccessControlResult_Rejected_RespSent && + res != ChipServerDelegateBase::kAccessControlResult_Rejected_Silent) + { + uint16_t statusCode = (msgInfo->PeerAuthMode == kChipAuthMode_None) ? Common::kStatus_AuthenticationRequired + : Common::kStatus_AccessDenied; + ChipServerBase::SendStatusReport(ec, kChipProtocol_Common, statusCode, CHIP_NO_ERROR); + } + + // Tell the caller the message should NOT be accepted. + return false; + } +} + +/** + * Send a CHIP status report with default message flags to the + * initiator on the specified exchange containing the status code in + * the specified profile and system error. + * + * @param[in] ec A pointer to the exchange context to send + * the status report on. + * + * @param[in] statusProfileId The profile for the specified status code. + * + * @param[in] statusCode The status code to send. + * + * @param[in] sysError The system error associated or correlated + * with the status code. + * + */ +CHIP_ERROR ChipServerBase::SendStatusReport(ExchangeContext * ec, uint32_t statusProfileId, uint16_t statusCode, + CHIP_ERROR sysError) +{ + const uint16_t sendFlags = 0; + + return SendStatusReport(ec, statusProfileId, statusCode, sysError, sendFlags); +} + +/** + * Send a CHIP status report with the provided message flags to the + * initiator on the specified exchange containing the status code in + * the specified profile and system error. + * + * @param[in] ec A pointer to the exchange context to send + * the status report on. + * + * @param[in] statusProfileId The profile for the specified status code. + * + * @param[in] statusCode The status code to send. + * + * @param[in] sysError The system error associated or correlated + * with the status code. + * + * @param[in] sendFlags Flags set by the application for the CHIP + * status report being sent. + * + */ +CHIP_ERROR ChipServerBase::SendStatusReport(ExchangeContext * ec, uint32_t statusProfileId, uint16_t statusCode, + CHIP_ERROR sysError, uint16_t sendFlags) +{ + CHIP_ERROR err; + PacketBuffer * respBuf; + uint8_t * p; + uint8_t respLen = 18; // sizeof(statusProfileId) + sizeof(statusCode) + StartContainer(1) + kTag_SystemErrorCode TLV Len (10), + // EndContainer (1) + + respBuf = PacketBuffer::NewWithAvailableSize(respLen); + VerifyOrExit(respBuf != NULL, err = CHIP_ERROR_NO_MEMORY); + VerifyOrDie(ec != NULL); + + p = respBuf->Start(); + LittleEndian::Write32(p, statusProfileId); + LittleEndian::Write16(p, statusCode); + respBuf->SetDataLength(6); + + if (sysError != CHIP_NO_ERROR) + { + TLVWriter statusWriter; + TLVType outerContainerType; + + statusWriter.Init(respBuf); + + err = statusWriter.StartContainer(AnonymousTag, kTLVType_Structure, outerContainerType); + SuccessOrExit(err); + + err = statusWriter.Put(ProfileTag(kChipProtocol_Common, Common::kTag_SystemErrorCode), (uint32_t) sysError); + SuccessOrExit(err); + + err = statusWriter.EndContainer(outerContainerType); + SuccessOrExit(err); + + err = statusWriter.Finalize(); + SuccessOrExit(err); + } + + err = ec->SendMessage(kChipProtocol_Common, Common::kMsgType_StatusReport, respBuf, sendFlags); + respBuf = NULL; + +exit: + if (respBuf != NULL) + PacketBuffer::Free(respBuf); + return err; +} + +/** + * Virtual method for determining message-level access control policy for incoming server request messages. + * + * This method is called by the CHIP server infrastructure to determine whether an incoming request message + * should be accepted and processed normally, or rejected. Delegate classes associated with CHIP server + * implementations must override this method to implement an appropriate access control policies for their + * protocols. Applications may further override this method to support custom policies beyond those provide + * by the standard server implementations. + * + * Implementations of this method are expected to return a result value of Accepted or Rejected based on + * the outcome of access control policy evaluation. Returning a result of Rejected causes a StatusReport + * to be sent to the requester containing the status Common/AccessDenied. Alternatively, method implementations + * can choose to send their own responses, which can be a StatusReport or any other type of message. In this + * case, the method should return a result of Reject_RespSent to signal that a response has already been sent. + * Finally, implementations can return Reject_Silent to indicate that the request should be rejected without + * sending a response to the requester. + * + * Classes that override the EnforceAccessControl() method are required in call cases to call the like-named + * method on their immediate parent class, be that the ChipServerDelegateBase class, or a class derived from + * that class. Overriding methods should first update the result value with their determination of the access + * control policy, and then call on their base class to make its determination. + * + * @param[in] ec The ExchangeContext over which the message was received. + * @param[in] msgProfileId The profile id of the received message. + * @param[in] msgType The message type of the received message. + * @param[in] msgInfo A ChipMessageInfo structure containing information about the received message. + * @param[inout] result An enumerated value describing the result of access control policy evaluation for + * the received message. Upon entry to the method, the value represents the tentative + * result at the current point in the evaluation process. Upon return, the result + * is expected to represent the final assessment of access control policy for the + * message. + */ +void ChipServerDelegateBase::EnforceAccessControl(ExchangeContext * ec, uint32_t msgProfileId, uint8_t msgType, + const ChipMessageInfo * msgInfo, AccessControlResult & result) +{ + // Mark the result as 'Final', confirming that the subclass properly called up to the base class. + result |= kAccessControlResult_IsFinal; +} + +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/CHIPServerBase.h b/src/lib/protocols/CHIPServerBase.h new file mode 100644 index 00000000000000..9112b13dcabcfe --- /dev/null +++ b/src/lib/protocols/CHIPServerBase.h @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 defines a common, base object that can be derived + * from but not instantiated itself. The object may be used for + * implementing CHIP protocol unsolicited responders (i.e., servers). + * It encapsulates validating authenticated requests and sending + * status reports. It also provides common data member storage for + * fabric state and an exchange manager. + * + */ + +#ifndef CHIPSERVERBASE_H_ +#define CHIPSERVERBASE_H_ + +#include +#include + +namespace chip { +namespace Protocols { + +class ChipServerDelegateBase; + +/** + * @class ChipServerBase + * + * @brief + * Common, base object for implementing CHIP protocol unsolicited + * responders (servers) that encapsulates validating + * authenticated requests and sending status reports and provides + * common data member storage for fabric state and an exchange + * manager. + * + */ +class ChipServerBase +{ +public: + ChipFabricState * FabricState; ///< [READ ONLY] Fabric state object + ChipExchangeManager * ExchangeMgr; ///< [READ ONLY] Exchange manager object + + static CHIP_ERROR SendStatusReport(ExchangeContext * ec, uint32_t statusProfileId, uint16_t statusCode, CHIP_ERROR sysError); + + static CHIP_ERROR SendStatusReport(ExchangeContext * ec, uint32_t statusProfileId, uint16_t statusCode, CHIP_ERROR sysError, + uint16_t sendFlags); + +protected: + ChipServerBase(void) {} + + bool EnforceAccessControl(ExchangeContext * ec, uint32_t msgProfileId, uint8_t msgType, const ChipMessageInfo * msgInfo, + ChipServerDelegateBase * delegate); + +private: + ChipServerBase(const ChipServerBase &); // not defined +}; + +/** + * A common base class for implementing CHIP server delegate objects. + */ +class ChipServerDelegateBase +{ + friend class ChipServerBase; + +protected: + ChipServerDelegateBase(void) {} + + typedef uint8_t AccessControlResult; + + enum + { + kAccessControlResult_NotDetermined = 0, ///< The message has not yet been accepted or rejected. + kAccessControlResult_Accepted = 1, ///< The message has been accepted. + kAccessControlResult_Rejected = 2, ///< The message has been rejected, and a default response should be sent. + kAccessControlResult_Rejected_RespSent = 3, ///< The message has been rejected, and a response has already been sent. + kAccessControlResult_Rejected_Silent = 4, ///< The message has been rejected, but no response should be sent. + }; + + virtual void EnforceAccessControl(ExchangeContext * ec, uint32_t msgProfileId, uint8_t msgType, const ChipMessageInfo * msgInfo, + AccessControlResult & result); + +private: + enum + { + kAccessControlResult_IsFinal = + 0x80, ///< A flag indicating that access control evaluation is complete and the result is final. + kAccessControlResult_FinalAccepted = kAccessControlResult_Accepted | kAccessControlResult_IsFinal + ///< Access control evaluation is complete and the message has been accepted. + }; +}; + +} // namespace Protocols +} // namespace chip + +#endif /* CHIPSERVERBASE_H_ */ diff --git a/src/lib/protocols/common/CHIPMessage.cpp b/src/lib/protocols/common/CHIPMessage.cpp new file mode 100644 index 00000000000000..c7310bcb467d31 --- /dev/null +++ b/src/lib/protocols/common/CHIPMessage.cpp @@ -0,0 +1,952 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 objects commonly used for the + * processing of Weave messages. + * + */ + +#include + +#include "CHIPMessage.h" + +using namespace chip; +using namespace chip::TLV; +using namespace chip::Protocols; + +//-------------------- definitions for the message iterator -------------------- + +/** + * The constructor method. + * + * @param aBuffer A message buffer to iterate over. + */ + +MessageIterator::MessageIterator(PacketBuffer * aBuffer) +{ + Retain(aBuffer); + + thePoint = aBuffer->Start(); +} + +/** + * @param aDestination A place to put a byte read off the buffer. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::readByte(uint8_t * aDestination) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasData(1)) + { + err = CHIP_NO_ERROR; + + *aDestination = READBYTE(thePoint); + } + + return err; +} + +/** + * @param aDestination A place to put a short read off the buffer. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::read16(uint16_t * aDestination) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasData(2)) + { + err = CHIP_NO_ERROR; + + READ16(thePoint, *aDestination); + } + + return err; +} + +/** + * @param aDestination A place to put a 32-bit value read off the buffer. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::read32(uint32_t * aDestination) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasData(4)) + { + err = CHIP_NO_ERROR; + + READ32(thePoint, *aDestination); + } + + return err; +} + +/** + * @param aDestination A place to put a 64-bit value read off the buffer. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::read64(uint64_t * aDestination) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + uint8_t * p; + + if (hasData(8)) + { + err = CHIP_NO_ERROR; + p = (uint8_t *) aDestination; + + for (int i = 0; i < 8; i++) + readByte(p++); + } + + return err; +} + +/** + * @param aLength The length of the string to be read. + * @param aString A place to put the string. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::readString(uint16_t aLength, char * aString) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasData(aLength)) + { + err = CHIP_NO_ERROR; + + for (uint16_t i = 0; i < aLength; i++) + { + *aString = READBYTE(thePoint); + aString++; + } + } + + return err; +} + +/** + * @param aLength The length of the byte string to be read. + * @param aByteString A place to put the bytes. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::readBytes(uint16_t aLength, uint8_t * aByteString) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasData(aLength)) + { + err = CHIP_NO_ERROR; + + for (uint16_t i = 0; i < aLength; i++) + { + *aByteString = READBYTE(thePoint); + aByteString++; + } + } + + return err; +} + +/** + * @param aValue A byte value to write out. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::writeByte(uint8_t aValue) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasRoom(1)) + { + err = CHIP_NO_ERROR; + + WRITEBYTE(thePoint, aValue); + finishWriting(); + } + + return err; +} + +/** + * @param aValue A short value to write out. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::write16(uint16_t aValue) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasRoom(2)) + { + err = CHIP_NO_ERROR; + + WRITE16(thePoint, aValue); + finishWriting(); + } + + return err; +} + +/** + * @param aValue A 32-bit value to write out. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::write32(uint32_t aValue) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasRoom(4)) + { + err = CHIP_NO_ERROR; + + WRITE32(thePoint, aValue); + finishWriting(); + } + + return err; +} + +/** + * @param aValue A 64-bit value to write out. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::write64(uint64_t aValue) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + uint8_t * p = (uint8_t *) &aValue; + + if (hasRoom(8)) + { + err = CHIP_NO_ERROR; + + for (int i = 0; i < 8; i++) + writeByte(*p++); + } + + return err; +} + +/** + * @param aLength The length of the string to write. + * @param aString The string itself. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::writeString(uint16_t aLength, char * aString) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasRoom(aLength)) + { + err = CHIP_NO_ERROR; + + for (uint16_t i = 0; i < aLength; i++) + { + WRITEBYTE(thePoint, *aString); + aString++; + } + finishWriting(); + } + + return err; +} + +/** + * @param aLength The length of the byte string to write. + * @param aString The byte string itself. + * + * @retval CHIP_NO_ERROR If it's all OK. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL If we're running past the end of the buffer. + */ + +CHIP_ERROR MessageIterator::writeBytes(uint16_t aLength, uint8_t * aByteString) +{ + CHIP_ERROR err = CHIP_ERROR_BUFFER_TOO_SMALL; + + if (hasRoom(aLength)) + { + err = CHIP_NO_ERROR; + + for (uint16_t i = 0; i < aLength; i++) + { + WRITEBYTE(thePoint, *aByteString); + aByteString++; + } + finishWriting(); + } + + return err; +} + +/** + * Increment a message iterator by 1 if there's room. + */ + +MessageIterator & MessageIterator::operator++(void) +{ + if (hasRoom(1)) + ++thePoint; + + return *this; +} + +/** + * @param inc An increment to apply to the message iterator. + * + * @return The iterator incremented by the given value if there's + * room, or else slammed right up against the end if there's not. + */ + +MessageIterator & MessageIterator::operator+(uint16_t inc) +{ + if (hasRoom(inc)) + thePoint += inc; + + else + thePoint += mBuffer->AvailableDataLength(); + + return *this; +} + +/** + * @param dec A decrement to apply to the message iterator. + * + * @return The iterator decremented by the given value if there's + * room, or else slammed right up against the beginning if there's not. + */ + +MessageIterator & MessageIterator::operator-(uint16_t dec) +{ + if (mBuffer->DataLength() > dec) + thePoint -= dec; + else + thePoint = mBuffer->Start(); + return *this; +} + +/** + * @param aMessageIterator Another message iterator to compare with. + */ + +bool MessageIterator::operator==(const MessageIterator & aMessageIterator) +{ + return (thePoint == aMessageIterator.thePoint && mBuffer == aMessageIterator.mBuffer); +} + +/** + * @param aMessageIterator Another message iterator to compare with. + */ + +bool MessageIterator::operator!=(const MessageIterator & aMessageIterator) +{ + return !(thePoint == aMessageIterator.thePoint && mBuffer == aMessageIterator.mBuffer); +} + +/** + * @return What we're looking at in the buffer. + */ + +uint8_t & MessageIterator::operator*(void) +{ + return *thePoint; +} + +/** + * Set the point to after any data currently in the buffer. + */ + +void MessageIterator::append(void) +{ + thePoint = mBuffer->Start() + mBuffer->DataLength(); +} + +/** + * @param inc An integer amount that may be read from the + * buffer. + * + * @retval true The buffer's current data length is greater than or equal + * to the given increment. + * @retval false Otherwise. + */ + +bool MessageIterator::hasData(uint16_t inc) +{ + return (thePoint + inc) <= (mBuffer->Start() + mBuffer->DataLength()); +} + +/** + * @param inc An integer amount that may be written to the + * buffer. + * + * @retval true The difference between the buffer's current data + * length and its maximum allowable data length, (its available data + * length), is less than or equal to the given increment. + * @retval false Otherwise. + */ + +bool MessageIterator::hasRoom(uint16_t inc) +{ + return inc <= (mBuffer->AvailableDataLength()); +} + +/** + * Adjust the buffer after writing. + */ + +void MessageIterator::finishWriting(void) +{ + mBuffer->SetDataLength((uint16_t)(thePoint - mBuffer->Start())); +} + +// -------------------- definitions for referenced strings -------------------- + +/** + * The no-arg constructor for referenced strings. + */ + +ReferencedString::ReferencedString(void) : RetainedPacketBuffer() +{ + theLength = 0; + theString = NULL; + isShort = false; +} + +/*** + * @fn CHIP_ERROR ReferencedString::init(uint16_t aLength, char *aString, System::PacketBuffer *aBuffer) + * @brief Initialize a ReferencedString + * + * Initialize the ReferencedString with a string and a PacketBuffer backing a that string. + * + * @param[in] aLength A length for the referenced string + * @param[in] aString A pointer to the string data (in the buffer) + * @param[in] aBuffer A messsage buffer in which the string resides + * + * @retval #CHIP_NO_ERROR On success + * @retval #CHIP_ERROR_INVALID_STRING_LENGTH The supplied string is too long + */ + +CHIP_ERROR ReferencedString::init(uint16_t aLength, char * aString, System::PacketBuffer * aBuffer) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (aLength > (aBuffer->AvailableDataLength() - aBuffer->DataLength())) + err = CHIP_ERROR_INVALID_STRING_LENGTH; + + else + { + Retain(aBuffer); + + theLength = aLength; + theString = aString; + isShort = false; + } + + return err; +} + +/*** + * @fn CHIP_ERROR ReferencedString::init(uint16_t aLength, char *aString) + * @brief Initialize a ReferencedString + * + * This initializer should be used if there's no message buffer because we're + * creating this object with an intention of immediately sending it. + * + * @note If the string passed in here is stack-allocated, any outgoing message + * created in this way must be sent before the stack context in which it was + * created is exited. + * + * @param[in] aLength A length for the referenced string + * @param[in] aString A pointer to the string data + * + * @retval #CHIP_NO_ERROR Unconditionally + */ + +CHIP_ERROR ReferencedString::init(uint16_t aLength, char * aString) +{ + theLength = aLength; + theString = aString; + + Release(); + + isShort = false; + + return CHIP_NO_ERROR; +} + +/*** + * @fn CHIP_ERROR ReferencedString::init(uint8_t aLength, char *aString, System::PacketBuffer *aBuffer) + * @overload + */ +CHIP_ERROR ReferencedString::init(uint8_t aLength, char * aString, System::PacketBuffer * aBuffer) +{ + if (aLength > (aBuffer->AvailableDataLength() - aBuffer->DataLength())) + return CHIP_ERROR_INVALID_STRING_LENGTH; + + Retain(aBuffer); + + theLength = (uint16_t) aLength; + theString = aString; + isShort = true; + + return CHIP_NO_ERROR; +} + +/*** + * @fn CHIP_ERROR ReferencedString::init(uint8_t aLength, char *aString) + * @overload + */ + +CHIP_ERROR ReferencedString::init(uint8_t aLength, char * aString) +{ + theLength = (uint16_t) aLength; + theString = aString; + + Release(); + + isShort = true; + + return CHIP_NO_ERROR; +} + +/** + * @param &i An iterator over the message being packed. + * @return CHIP_ERROR + */ + +CHIP_ERROR ReferencedString::pack(MessageIterator & i) +{ + CHIP_ERROR e; + + if (isShort) + e = i.writeByte((uint8_t) theLength); + + else + e = i.write16(theLength); + + if (e == CHIP_NO_ERROR) + e = i.writeString(theLength, theString); + + return e; +} + +/** + * @param &i An iterator over the message being parsed. + * @param &aString A place to put the result of parsing. + * + * @retval CHIP_NO_ERROR String parsed successfully. + * @retval CHIP_ERROR_INVALID_STRING_LENGTH The string is too long for the buffer + * (this should never happen). + */ + +CHIP_ERROR ReferencedString::parse(MessageIterator & i, ReferencedString & aString) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint16_t len = 0; + + if (aString.isShort) + i.readByte((uint8_t *) &len); + + else + i.read16(&len); + + if (i.hasRoom(len)) + { + aString.theLength = len; + aString.theString = (char *) i.thePoint; + aString.Retain(i.GetBuffer()); + + // we need to skip over the string + + (i.thePoint) += len; + } + + else + err = CHIP_ERROR_INVALID_STRING_LENGTH; + + return err; +} + +/** + * @param &aReferencedString A string to check against. + * + * @retval true The strings are equal. + * @retval false The strings are not equal. + */ + +bool ReferencedString::operator==(const ReferencedString & aReferencedString) const +{ + bool result = false; + + if (theLength == aReferencedString.theLength) + { + for (int i = 0; i < theLength; i++) + { + if (theString[i] != aReferencedString.theString[i]) + goto exit; + } + + result = true; + } + +exit: + + return result; +} + +/** + * @return A printable string + */ + +char * ReferencedString::printString(void) +{ + theString[theLength] = 0; + + return theString; +} + +/** + *-------------------- definitions for TLV data -------------------- + */ + +/** + * The no-arg constructor for TLV data. Delivers a free/uninitialized + * object which must be subjected to one of the init() methods defined + * here in order to be useful. + */ + +ReferencedTLVData::ReferencedTLVData(void) : RetainedPacketBuffer() +{ + theLength = 0; + theMaxLength = 0; + theData = NULL; + theWriteCallback = NULL; + theAppState = NULL; +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::init(System::PacketBuffer *aBuffer) + * + * @brief Initialize the ReferencedTLVData object given a PacketBuffer + * + * Initialize a ReferencedTLVData object given a buffer full of + * TLV. This assumes that the buffer ONLY contains TLV. + * + * @param [in] aBuffer A message buffer in which the TLV resides. + * + * @retval #CHIP_NO_ERROR Unconditionally + */ + +CHIP_ERROR ReferencedTLVData::init(System::PacketBuffer * aBuffer) +{ + Retain(aBuffer); + + theData = mBuffer->Start(); + theLength = mBuffer->DataLength(); + theMaxLength = mBuffer->MaxDataLength(); + + theWriteCallback = NULL; + theAppState = NULL; + + return CHIP_NO_ERROR; +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::init(MessageIterator &i) + * + * @brief Initialize a ReferencedTLVData object given a MessageIterator. + * + * Initialize a ReferencedTLVData object given a MessageIterator. In + * this case, the TLV is that last portion of the buffer and we pass in + * a message iterator that's pointing to it. + * + * @param [in] i A message iterator pointing to TLV to be extracted. + * + * @retval #CHIP_NO_ERROR Unconditionally + */ + +CHIP_ERROR ReferencedTLVData::init(MessageIterator & i) +{ + System::PacketBuffer * theBuffer = i.GetBuffer(); + + Retain(theBuffer); + + theData = i.thePoint; + theLength = theBuffer->DataLength() - (i.thePoint - mBuffer->Start()); + theMaxLength = theBuffer->MaxDataLength(); + + theWriteCallback = NULL; + theAppState = NULL; + + return CHIP_NO_ERROR; +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::init(uint16_t aLength, uint16_t aMaxLength, uint8_t *aByteString) + * + * @brief Initialize a ReferencedTLVObject given a byte string. + * + * Initialize ReferencedTLVData object with a byte string containing + * TLV. This initializer is the one we use if there's no PacketrBuffer + * because we're creating one of these to pack and send. + * + * @note if the string passed in here is stack-allocated, any + * outgoing message created in this way must be sent before the stack + * context in which it was created is exited. + * + * @param[in] aLength A length for the TLV data + * @param[in] aMaxLength The total length of the buffer + * @param[in] aByteString A pointer to the string data + * + * @retval #CHIP_NO_ERROR Unconditionally + */ + +CHIP_ERROR ReferencedTLVData::init(uint16_t aLength, uint16_t aMaxLength, uint8_t * aByteString) +{ + theLength = aLength; + theMaxLength = aMaxLength; + theData = aByteString; + + Release(); + + theWriteCallback = NULL; + theAppState = NULL; + + return CHIP_NO_ERROR; +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::init(TLVWriteCallback aWriteCallback, void *anAppState) + * + * @brief Initialize a RefererencedTLVData object given a callback function. + * + * Initialize a ReferencedTLVData object. Instead of explicitly + * supplying the data, this version provides function, the write + * callback, and a reference object, which will be passed to it, along + * with a TLVWriter object, when the referenced data is supposed to be + * packed and sent. The signature of that callback is: + * + * @code + * typedef void (*TLVWriteCallback)(TLV::TLVWriter &aWriter, void *aAppState); + * @endcode + * @param [in] aWriteCallback the function to be + * called when it's time to write some TLV. + * @param [in] anAppState an application state object to be + * passed to the callback along with the writer. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_ARGUMENT If the write callback is not supplied. + */ + +CHIP_ERROR ReferencedTLVData::init(TLVWriteCallback aWriteCallback, void * anAppState) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + if (aWriteCallback != NULL) + { + theWriteCallback = aWriteCallback; + theAppState = anAppState; + } + + else + err = CHIP_ERROR_INVALID_ARGUMENT; + + theLength = 0; + theMaxLength = 0; + theData = NULL; + mBuffer = NULL; + + return err; +} + +/** + * Free a ReferencedTLVData object, which is to say, undefine it. + * + */ +void ReferencedTLVData::free(void) +{ + RetainedPacketBuffer::Release(); + + /** + * in this case you have to clear out the write callback and app + * state as well since that may be how the data is getting generated. + */ + + theWriteCallback = NULL; + theAppState = NULL; + + // and the rest of it for good measure + + theLength = 0; + theMaxLength = 0; + theData = NULL; +} + +/** + * Check if a ReferencedTLVData object is "free", i.e. undefined. + * + * @return true if the object is undefined, false otherwise. + */ + +bool ReferencedTLVData::isFree(void) +{ + return (mBuffer == NULL && theWriteCallback == NULL && theAppState == NULL); +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::pack(MessageIterator &i) + * + * @brief Pack a ReferencedTLVData object using a TLVWriter. + * + * @param [in] i An iterator over the message being packed. + * @param [in] maxLen The maximum number of bytes that should be written to the output buffer. + * + * @return a CHIP_ERROR - CHIP_NO_ERROR if all goes well, otherwise + * an error reflecting an inability of the writer to write the + * relevant bytes. Note that the write callback is not allowed to + * return an error and so fails silently. + */ + +CHIP_ERROR ReferencedTLVData::pack(MessageIterator & i, uint32_t maxLen) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBuffer * theBuffer = i.GetBuffer(); + uint16_t oldDataLength = theBuffer->DataLength(); + TLVWriter writer; + + if (theWriteCallback != NULL) + { + theData = i.thePoint; + writer.Init(theBuffer, maxLen); + theWriteCallback(writer, theAppState); + theLength = theBuffer->DataLength() - oldDataLength; + i.thePoint += theLength; + } + else + err = i.writeBytes(theLength, theData); + + return err; +} + +/** + * @fn CHIP_ERROR ReferencedTLVData::parse(MessageIterator &i, ReferencedTLVData &aTarget) + * + * @brief Parse a ReferencedTLVData object from a supplied MessageIterator + * + * Parse a ReferenceTLVData object from a MessageIterator object + * assumed to be pointing at the TLV portion of a message. + * + * Note that no actual "parsing" is done here since the TLV is left in + * the buffer and not manipulated at all. This method mainly just sets + * up the ReferencedTLVData structure for later use. + * + * @param [in] i An iterator over the message being + * parsed. + * @param [out] aTarget A place to put the result + * of parsing. + * + * @retval #CHIP_NO_ERROR Unconditionally + */ + +CHIP_ERROR ReferencedTLVData::parse(MessageIterator & i, ReferencedTLVData & aTarget) +{ + PacketBuffer * buff = i.GetBuffer(); + + aTarget.Retain(buff); + + aTarget.theLength = buff->DataLength() - (i.thePoint - buff->Start()); + + if (aTarget.theLength != 0) + aTarget.theData = i.thePoint; + + else + aTarget.theData = NULL; + + // we need to skip over the data + + (i.thePoint) += aTarget.theLength; + + return CHIP_NO_ERROR; +} + +/** + * Check a ReferencedTLVData object against another for equality. + * + * Note that this only really makes sense in the case of two objects + * that have actual data in them backed by a buffer or string. + * + * @param [in] Another an object to check against + * + * @retval true The objects are equal. + * @retval false The objects strings are not equal. + */ + +bool ReferencedTLVData::operator==(const ReferencedTLVData & another) const +{ + bool result = false; + + if (theLength == another.theLength) + { + for (int i = 0; i < theLength; i++) + { + if (theData[i] != another.theData[i]) + goto exit; + } + + result = true; + } + +exit: + + return result; +} diff --git a/src/lib/protocols/common/CHIPMessage.h b/src/lib/protocols/common/CHIPMessage.h index a4645e61ac38ec..ded42c8e737259 100644 --- a/src/lib/protocols/common/CHIPMessage.h +++ b/src/lib/protocols/common/CHIPMessage.h @@ -117,7 +117,6 @@ } while (0) namespace chip { - namespace Protocols { /** diff --git a/src/lib/protocols/common/RetainedPacketBuffer.cpp b/src/lib/protocols/common/RetainedPacketBuffer.cpp new file mode 100644 index 00000000000000..5e1c182e71aba0 --- /dev/null +++ b/src/lib/protocols/common/RetainedPacketBuffer.cpp @@ -0,0 +1,136 @@ +/* + * + * Copyright (c) 2013-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 a base class that serves as a convenience + * object for automatically reference counting a System::PacketBuffer. + * + */ + +#include "CHIPMessage.h" + +namespace chip { +namespace Protocols { + +/** + * This is the class default (void) constructor. + * + */ +RetainedPacketBuffer::RetainedPacketBuffer(void) +{ + mBuffer = NULL; +} + +/** + * This is a class copy constructor. It increases the reference + * count, creating a strong reference to the buffer associated with + * the copied object. + * + * @param[in] aRetainedPacketBuffer A constant reference to the object to be + * copied. + * + */ +RetainedPacketBuffer::RetainedPacketBuffer(const RetainedPacketBuffer & aRetainedPacketBuffer) +{ + mBuffer = NULL; + + Retain(aRetainedPacketBuffer.mBuffer); +} + +/** + * This is the class destructor. It removes the strong reference to + * the associated buffer. + * + */ +RetainedPacketBuffer::~RetainedPacketBuffer(void) +{ + Release(); +} + +/** + * This is a class assignment operator. As long as the assigned + * object is not the current object, this creates a strong reference + * to the buffer associated with the copied object while, if + * necessary, removing the strong reference to the buffer associated + * with this object. + * + * @param[inout] aRetainedPacketBuffer A read-only reference to the object + * to assign to this one. If + * the reference is not this + * object, the source object's + * associated buffer is + * retained, displacing the + * currently associated buffer. + * + * @return a read-only reference to the current object. + * + */ +RetainedPacketBuffer & RetainedPacketBuffer::operator=(const RetainedPacketBuffer & aRetainedPacketBuffer) +{ + if (this != &aRetainedPacketBuffer) + Retain(aRetainedPacketBuffer.mBuffer); + + return *this; +} + +/** + * Verify whether or not this object is retaining a buffer. + * + * @return @p true if the object is retaining a buffer; otherwise, @p + * false. + * + */ +bool RetainedPacketBuffer::IsRetaining(void) const +{ + return (mBuffer != NULL); +} + +/** + * Create a strong reference to the specified packet buffer and, if + * necessary, displace and remove the strong reference to another + * buffer associated with this object. + * + */ +void RetainedPacketBuffer::Retain(System::PacketBuffer * aBuffer) +{ + if (aBuffer != NULL) + { + aBuffer->AddRef(); + } + + if (mBuffer != NULL) + { + System::PacketBuffer::Free(mBuffer); + } + + mBuffer = aBuffer; +} + +/** + * Remove the strong reference to the buffer associated with the + * object, making this object available to retain another buffer. + * + */ +void RetainedPacketBuffer::Release(void) +{ + Retain(NULL); +} + +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/security/CHIPApplicationKeys.cpp b/src/lib/protocols/security/CHIPApplicationKeys.cpp new file mode 100644 index 00000000000000..8b37a0bc7ab34b --- /dev/null +++ b/src/lib/protocols/security/CHIPApplicationKeys.cpp @@ -0,0 +1,242 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * 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 interfaces for deriving and retrieving + * CHIP constituent and application group keys. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include +#include + +#include "CHIPApplicationKeys.h" + +namespace chip { +namespace Protocols { +namespace Security { +namespace AppKeys { + +/** + * Get application group master key ID given application group global ID. + * + * @param[in] groupGlobalId The application group global ID. + * @param[in] groupKeyStore A pointer to the group key store object. + * @param[out] groupMasterKeyId The application group master key ID. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_ARGUMENT + * If pointer to the group key store is not provided. + * @retval #CHIP_ERROR_UNSUPPORTED_WEAVE_FEATURE + * If FabricState object wasn't initialized with fully + * functional group key store. + * @retval #CHIP_ERROR_KEY_NOT_FOUND + * If a group key with specified global ID is not found + * in the platform key store. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GetAppGroupMasterKeyId(uint32_t groupGlobalId, GroupKeyStoreBase * groupKeyStore, uint32_t & groupMasterKeyId) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR LogGroupKeys(GroupKeyStoreBase * groupKeyStore) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Initialize local group key store parameters. + */ +void GroupKeyStoreBase::Init(void) +{ + LastUsedEpochKeyId = ChipKeyId::kNone; + NextEpochKeyStartTime = UINT32_MAX; +} + +/** + * Returns current key ID. + * Sets member variables associated with epoch keys to the default values when any change + * (delete or store) happens to the set of application epoch keys. It is the responsibility + * of the subclass that implements StoreGroupKey(), DeleteGroupKey(), and + * DeleteGroupKeysOfAType() functions to call this method. + */ +void GroupKeyStoreBase::OnEpochKeysChange(void) +{ + LastUsedEpochKeyId = ChipKeyId::kNone; + NextEpochKeyStartTime = UINT32_MAX; +} + +/** + * Get current platform UTC time in seconds. + * + * @param[out] utcTime A reference to the time value. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_SYSTEM_ERROR_NOT_SUPPORTED + * If platform does not support a real time clock. + * @retval #CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED + * If the system's real time clock is not synchronized to + * an accurate time source. + * @retval other Other Weave or platform error codes. + */ +CHIP_ERROR GroupKeyStoreBase::GetCurrentUTCTime(uint32_t & utcTime) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Returns current key ID. + * Finds current epoch key based on the current system time and the start time parameter + * of each epoch key. If system doesn't have valid, accurate time then last-used epoch key + * ID is returned. + * + * @param[in] keyId The application key ID. + * @param[out] curKeyId The application current key ID. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_KEY_ID + * If the input key ID had an invalid value. + * @retval #CHIP_ERROR_KEY_NOT_FOUND + * If epoch keys are not found in the platform key store. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GroupKeyStoreBase::GetCurrentAppKeyId(uint32_t keyId, uint32_t & curKeyId) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Get application group key. + * This function derives or retrieves application group keys. Key types supported by + * this function are: fabric secret, root key, epoch key, group master key, and intermediate key. + * + * @param[in] keyId The group key ID. + * @param[out] groupKey A reference to the group key object. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_KEY_ID + * If the requested key has invalid key ID. + * @retval #CHIP_ERROR_INVALID_ARGUMENT + * If the platform key store returns invalid key parameters. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GroupKeyStoreBase::GetGroupKey(uint32_t keyId, ChipGroupKey & groupKey) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Derive fabric/client root key. + * Fabric and client root keys are derived from fabric secret, which is retrieved + * from the platform key store. + * + * @param[in] rootKeyId The key ID associated with the requested root key. + * @param[out] rootKey A reference to the key material object. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_KEY_ID + * If the requested key has invalid key ID. + * @retval #CHIP_ERROR_INVALID_ARGUMENT + * If the platform key store returns invalid key parameters. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GroupKeyStoreBase::DeriveFabricOrClientRootKey(uint32_t rootKeyId, ChipGroupKey & rootKey) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Derive application intermediate key. + * The intermediate key is derived from the root key and epoch key material specified + * in the @a keyId input. + * + * @param[in] keyId The requested intermediate key ID. + * @param[out] intermediateKey A reference to the key material object. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_INVALID_KEY_ID + * If the requested key has invalid key ID. + * @retval #CHIP_ERROR_INVALID_ARGUMENT + * If the platform key store returns invalid key parameters. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GroupKeyStoreBase::DeriveIntermediateKey(uint32_t keyId, ChipGroupKey & intermediateKey) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +/** + * Derives application key. + * Three types of application keys are supported: current application key, rotating + * application key and static application key. When current application key is requested + * the function finds and uses the current epoch key based on the current system time and + * the start time parameter of each epoch key. + * + * @param[inout] keyId A reference to the requested key ID. When current application + * key is requested this field is updated to reflect the new + * type (rotating application key) and the actual epoch key ID + * that was used to generate application key. + * @param[in] keySalt A pointer to a buffer with application key salt value. + * @param[in] saltLen The length of the application key salt. + * @param[in] keyDiversifier A pointer to a buffer with application key diversifier value. + * @param[in] diversifierLen The length of the application key diversifier. + * @param[out] appKey A pointer to a buffer where the derived key will be written. + * @param[in] keyBufSize The length of the supplied key buffer. + * @param[in] keyLen The length of the requested key material. + * @param[out] appGroupGlobalId The application group global ID of the associated key. + * + * @retval #CHIP_NO_ERROR On success. + * @retval #CHIP_ERROR_BUFFER_TOO_SMALL + * If the provided key buffer size is not sufficient. + * @retval #CHIP_ERROR_INVALID_KEY_ID + * If the requested key has invalid key ID. + * @retval #CHIP_ERROR_INVALID_ARGUMENT + * If the platform key store returns invalid key parameters + * or key identifier has invalid value. + * @retval other Other platform-specific errors returned by the platform + * key store APIs. + * + */ +CHIP_ERROR GroupKeyStoreBase::DeriveApplicationKey(uint32_t & keyId, const uint8_t * keySalt, uint8_t saltLen, + const uint8_t * keyDiversifier, uint8_t diversifierLen, uint8_t * appKey, + uint8_t keyBufSize, uint8_t keyLen, uint32_t & appGroupGlobalId) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +} // namespace AppKeys +} // namespace Security +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/security/CHIPDummyGroupKeyStore.cpp b/src/lib/protocols/security/CHIPDummyGroupKeyStore.cpp new file mode 100644 index 00000000000000..c249b3f4b827e0 --- /dev/null +++ b/src/lib/protocols/security/CHIPDummyGroupKeyStore.cpp @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * 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 interfaces for the default group key store. + * + */ + +#include "CHIPDummyGroupKeyStore.h" +#include + +namespace chip { +namespace Protocols { +namespace Security { +namespace AppKeys { + +DummyGroupKeyStore::DummyGroupKeyStore(void) +{ + Init(); +} + +CHIP_ERROR DummyGroupKeyStore::RetrieveGroupKey(uint32_t keyId, ChipGroupKey & key) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::StoreGroupKey(const ChipGroupKey & key) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::DeleteGroupKey(uint32_t keyId) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::DeleteGroupKeysOfAType(uint32_t keyType) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::EnumerateGroupKeys(uint32_t keyType, uint32_t * keyIds, uint8_t keyIdsArraySize, uint8_t & keyCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::Clear(void) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::RetrieveLastUsedEpochKeyId(void) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::StoreLastUsedEpochKeyId(void) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR DummyGroupKeyStore::GetCurrentUTCTime(uint32_t & utcTime) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +} // namespace AppKeys +} // namespace Security +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/status-report/StatusReportProtocol.cpp b/src/lib/protocols/status-report/StatusReportProtocol.cpp new file mode 100644 index 00000000000000..d26ed961a9085f --- /dev/null +++ b/src/lib/protocols/status-report/StatusReportProtocol.cpp @@ -0,0 +1,206 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-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 methods for the Nest Weave Status Report + * profile. + */ + +#include +#include +#include +#include + +#include "StatusReportProtocol.h" + +using namespace chip; +using namespace chip::TLV; +using namespace chip::Protocols; +using namespace chip::Protocols::Common; + +namespace chip { +namespace Protocols { +namespace StatusReporting { + +StatusReport::StatusReport(void) +{ + mProtocolId = 0; + mStatusCode = 0; + mError = CHIP_NO_ERROR; +} + +StatusReport::~StatusReport(void) +{ + mProtocolId = 0; + mStatusCode = 0; + mError = CHIP_NO_ERROR; +} + +CHIP_ERROR StatusReport::init(uint32_t aProfileId, uint16_t aCode, ReferencedTLVData * aInfo) +{ + mProtocolId = aProfileId; + mStatusCode = aCode; + mError = CHIP_NO_ERROR; + + if (aInfo) + mAdditionalInfo = *aInfo; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR StatusReport::init(CHIP_ERROR aError) +{ + if (aError == CHIP_NO_ERROR) + { + mProtocolId = kChipProtocol_Common; + mStatusCode = kStatus_Success; + } + + else + { + mProtocolId = kChipProtocol_Common; + mStatusCode = kStatus_InternalError; + mError = aError; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR StatusReport::pack(PacketBuffer * aBuffer, uint32_t maxLen) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + MessageIterator i(aBuffer); + TLVWriter writer; + + i.append(); + + err = i.write32(mProtocolId); + SuccessOrExit(err); + + err = i.write16(mStatusCode); + SuccessOrExit(err); + + /* + * the assumption here is that EITHER there's + * an error code that wants to be included as + * metadata OR there's additional info passed + * in at initialization time, which may include + * an error, OR there's none of the above, in + * which case the else clause her writes nothing + */ + + if (mError != CHIP_NO_ERROR) + { + writer.Init(aBuffer); + + err = StartMetaData(writer); + SuccessOrExit(err); + + err = AddErrorCode(writer, mError); + SuccessOrExit(err); + + err = EndMetaData(writer); + SuccessOrExit(err); + + /* + * this is a bit of a hack. we basically set this + * so that packedLength() below will return the right + * number at least if we call it AFTER the thing has + * been packed. it's not clear we ever use this. + */ + + mAdditionalInfo.theLength = writer.GetLengthWritten(); + } + + else + { + err = mAdditionalInfo.pack(i, maxLen - 6); + } + +exit: + return err; +} + +inline uint16_t StatusReport::packedLength(void) +{ + return sizeof(mProtocolId) + sizeof(mStatusCode) + mAdditionalInfo.theLength; +} + +CHIP_ERROR StatusReport::parse(PacketBuffer * aBuffer, StatusReport & aDestination) +{ + CHIP_ERROR err; + MessageIterator i(aBuffer); + + err = i.read32(&aDestination.mProtocolId); + SuccessOrExit(err); + + err = i.read16(&aDestination.mStatusCode); + SuccessOrExit(err); + + err = ReferencedTLVData::parse(i, aDestination.mAdditionalInfo); + +exit: + return err; +} + +bool StatusReport::operator==(const StatusReport & another) const +{ + return ((mProtocolId == another.mProtocolId) && (mStatusCode == another.mStatusCode)); +} + +/* + * the universal, gold standard for success is + * : : + */ + +bool StatusReport::success(void) +{ + return (mProtocolId == kChipProtocol_Common && mStatusCode == kStatus_Success); +} + +CHIP_ERROR StatusReport::StartMetaData(chip::TLV::TLVWriter & aWriter) +{ + TLVType metaDataContainer; + + return aWriter.StartContainer(AnonymousTag, kTLVType_Structure, metaDataContainer); +} + +CHIP_ERROR StatusReport::EndMetaData(chip::TLV::TLVWriter & aWriter) +{ + CHIP_ERROR err; + TLVType metaDataContainer = kTLVType_Structure; + + err = aWriter.EndContainer(metaDataContainer); + SuccessOrExit(err); + + err = aWriter.Finalize(); + +exit: + return err; +} + +CHIP_ERROR StatusReport::AddErrorCode(chip::TLV::TLVWriter & aWriter, CHIP_ERROR aError) +{ + return aWriter.Put(CommonTag(kTag_SystemErrorCode), aError); +} + +} // namespace StatusReporting +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/status-report/StatusReportProtocol.h b/src/lib/protocols/status-report/StatusReportProtocol.h index 0b068a9df9be42..5417ae1a0adb2f 100644 --- a/src/lib/protocols/status-report/StatusReportProtocol.h +++ b/src/lib/protocols/status-report/StatusReportProtocol.h @@ -37,6 +37,7 @@ #define _STATUS_REPORT_PROTOCOL_H #include +#include #include /** diff --git a/src/lib/support/ErrorStr.cpp b/src/lib/support/ErrorStr.cpp index 4d150a0a85aa22..4023f2330c4e94 100644 --- a/src/lib/support/ErrorStr.cpp +++ b/src/lib/support/ErrorStr.cpp @@ -45,6 +45,13 @@ static char sErrorStr[CHIP_CONFIG_ERROR_STR_SIZE]; */ static ErrorFormatter * sErrorFormatterList = NULL; +DLL_EXPORT const char * StatusReportStr(uint32_t protocolId, uint16_t statusCode) +{ + (void) snprintf(sErrorStr, sizeof(sErrorStr), "0x%" PRIx32 " 0x%" PRIx16, protocolId, statusCode); + + return sErrorStr; +} + /** * This routine returns a human-readable NULL-terminated C string * describing the provided error. diff --git a/src/lib/support/ErrorStr.h b/src/lib/support/ErrorStr.h index 482d706276c545..0bdab55359d63d 100644 --- a/src/lib/support/ErrorStr.h +++ b/src/lib/support/ErrorStr.h @@ -45,7 +45,7 @@ extern void RegisterErrorFormatter(ErrorFormatter * errFormatter); extern void DeregisterErrorFormatter(ErrorFormatter * errFormatter); extern void FormatError(char * buf, uint16_t bufSize, const char * subsys, int32_t err, const char * desc); -extern const char * StatusReportStr(uint32_t profileId, uint16_t statusCode); +extern const char * StatusReportStr(uint32_t protocolId, uint16_t statusCode); } // namespace chip diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 259ff20fc3a1bf..b0dea16dc4395b 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -49,6 +49,7 @@ if (chip_device_platform != "none") { chip_device_config_enable_wpa = chip_enable_wifi defines = [ + "CHIP_ENABLE_MESSAGE_LAYER=1", "CHIP_DEVICE_CONFIG_ENABLE_WPA=${chip_device_config_enable_wpa}", "CHIP_ENABLE_OPENTHREAD=${chip_enable_openthread}", "CHIP_WITH_GIO=${chip_with_gio}", @@ -164,6 +165,7 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "${chip_root}/src/inet", "${chip_root}/src/lib/core", "${chip_root}/src/lib/core:chip_config_header", + "${chip_root}/src/lib/message", "${chip_root}/src/lib/support", "${nlio_root}:nlio", ]