From 423575fceb79c2e5c078a9e065fbdc0ab20e6304 Mon Sep 17 00:00:00 2001 From: kangping Date: Wed, 14 Apr 2021 23:16:08 +0800 Subject: [PATCH] [meshcop] support Thread 1.2 Security Policy flags (#6320) --- include/openthread/dataset.h | 28 ++- include/openthread/instance.h | 2 +- src/cli/README_DATASET.md | 10 +- src/cli/cli_dataset.cpp | 219 +++++++++++------- src/cli/cli_dataset.hpp | 3 + src/core/mac/mac.cpp | 2 +- src/core/meshcop/dataset.cpp | 25 +- src/core/meshcop/dataset.hpp | 17 +- src/core/meshcop/dataset_manager.cpp | 6 +- src/core/meshcop/dataset_manager_ftd.cpp | 4 +- src/core/meshcop/meshcop_tlvs.cpp | 27 +++ src/core/meshcop/meshcop_tlvs.hpp | 55 ++--- src/core/thread/key_manager.cpp | 130 +++++++++-- src/core/thread/key_manager.hpp | 182 +++++++-------- src/core/thread/mle.cpp | 2 +- src/core/thread/mle_router.cpp | 2 +- src/lib/spinel/radio_spinel_impl.hpp | 12 +- src/lib/spinel/spinel.h | 4 +- src/ncp/ncp_base_mtd.cpp | 20 +- .../Cert_5_8_04_SecurityPolicyTLV.py | 32 ++- tests/scripts/thread-cert/node.py | 5 + tools/otci/otci/otci.py | 2 +- 22 files changed, 478 insertions(+), 311 deletions(-) diff --git a/include/openthread/dataset.h b/include/openthread/dataset.h index 8ec38d232..8ef415936 100644 --- a/include/openthread/dataset.h +++ b/include/openthread/dataset.h @@ -131,22 +131,20 @@ typedef struct otPskc otPskc; */ typedef struct otSecurityPolicy { - uint16_t mRotationTime; ///< The value for thrKeyRotation in units of hours - uint8_t mFlags; ///< Flags as defined in Thread 1.1 Section 8.10.1.15 -} otSecurityPolicy; + uint16_t mRotationTime; ///< The value for thrKeyRotation in units of hours. -/** - * This enumeration defines the Security Policy TLV flags. - * - */ -enum -{ - OT_SECURITY_POLICY_OBTAIN_MASTER_KEY = 1 << 7, ///< Obtaining the Master Key - OT_SECURITY_POLICY_NATIVE_COMMISSIONING = 1 << 6, ///< Native Commissioning - OT_SECURITY_POLICY_ROUTERS = 1 << 5, ///< Routers enabled - OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER = 1 << 4, ///< External Commissioner allowed - OT_SECURITY_POLICY_BEACONS = 1 << 3, ///< Beacons enabled -}; + bool mObtainMasterKeyEnabled : 1; ///< Obtaining the Master Key for out-of-band commissioning is enabled + bool mNativeCommissioningEnabled : 1; ///< Native Commissioning using PSKc is allowed + bool mRoutersEnabled : 1; ///< Thread 1.0/1.1.x Routers are enabled + bool mExternalCommissioningEnabled : 1; ///< External Commissioner authentication is allowed + bool mBeaconsEnabled : 1; ///< Thread 1.0/1.1.x Beacons are enabled + bool mCommercialCommissioningEnabled : 1; ///< Commercial Commissioning is enabled + bool mAutonomousEnrollmentEnabled : 1; ///< Autonomous Enrollment is enabled + bool mMasterKeyProvisioningEnabled : 1; ///< Network Master-key Provisioning is enabled + bool mTobleLinkEnabled : 1; ///< ToBLE link is enabled + bool mNonCcmRoutersEnabled : 1; ///< Non-CCM Routers enabled + uint8_t mVersionThresholdForRouting : 3; ///< Version-threshold for Routing +} otSecurityPolicy; /** * This type represents Channel Mask. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 35438f424..12ea6e534 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (99) +#define OPENTHREAD_API_VERSION (100) /** * @addtogroup api-instance diff --git a/src/cli/README_DATASET.md b/src/cli/README_DATASET.md index a2896dd2d..534fadc75 100644 --- a/src/cli/README_DATASET.md +++ b/src/cli/README_DATASET.md @@ -366,7 +366,7 @@ Usage: `dataset mgmtgetcommand [address ] [TLV lis Send MGMT_ACTIVE_GET or MGMT_PENDING_GET. ```bash -> dataset mgmtgetcommand active address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp -x 0c030001ff +> dataset mgmtgetcommand active address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp securitypolicy Done ``` @@ -377,7 +377,7 @@ Usage: `dataset mgmtsetcommand [TLV Type list] [-x]` Send MGMT_ACTIVE_SET or MGMT_PENDING_SET. ```bash -> dataset mgmtsetcommand active activetimestamp 123 -x 0c030001ff +> dataset mgmtsetcommand active activetimestamp 123 securitypolicy 1 onrcb Done ``` @@ -496,7 +496,7 @@ Done ### securitypolicy -Usage: `dataset securitypolicy [ [onrcb]]` +Usage: `dataset securitypolicy [ [onrcbCepR]]` Get security policy. @@ -513,6 +513,10 @@ Set security policy. - r: Thread 1.x Routers are enabled. - c: External Commissioner authentication is allowed using PSKc. - b: Thread 1.x Beacons are enabled. +- C: Thread 1.2 Commercial Commissioning is enabled. +- e: Thread 1.2 Autonomous Enrollment is enabled. +- p: Thread 1.2 Network Master Key Provisioning is enabled. +- R: Non-CCM routers are allowed in Thread 1.2 CCM networks. ```bash > dataset securitypolicy 672 onrcb diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index ddbe2ff4f..e5a28f69a 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -126,33 +126,8 @@ otError Dataset::Print(otOperationalDataset &aDataset) if (aDataset.mComponents.mIsSecurityPolicyPresent) { - mInterpreter.OutputFormat("Security Policy: %d, ", aDataset.mSecurityPolicy.mRotationTime); - - if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_OBTAIN_MASTER_KEY) - { - mInterpreter.OutputFormat("o"); - } - - if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_NATIVE_COMMISSIONING) - { - mInterpreter.OutputFormat("n"); - } - - if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_ROUTERS) - { - mInterpreter.OutputFormat("r"); - } - - if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER) - { - mInterpreter.OutputFormat("c"); - } - - if (aDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_BEACONS) - { - mInterpreter.OutputFormat("b"); - } - + mInterpreter.OutputFormat("Security Policy: ", aDataset.mSecurityPolicy.mRotationTime); + OutputSecurityPolicy(aDataset.mSecurityPolicy); mInterpreter.OutputLine(""); } @@ -620,6 +595,14 @@ otError Dataset::ProcessMgmtSetCommand(uint8_t aArgsLength, char *aArgs[]) dataset.mComponents.mIsChannelMaskPresent = true; SuccessOrExit(error = ParseAsUint32(aArgs[index], dataset.mChannelMask)); } + else if (strcmp(aArgs[index], "securitypolicy") == 0) + { + VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS); + SuccessOrExit(error = ParseSecurityPolicy(dataset.mSecurityPolicy, aArgs[index], + index + 1 < aArgsLength ? aArgs[index + 1] : nullptr)); + dataset.mComponents.mIsSecurityPolicyPresent = true; + ++index; + } else if (strcmp(aArgs[index], "-x") == 0) { uint16_t length; @@ -703,6 +686,10 @@ otError Dataset::ProcessMgmtGetCommand(uint8_t aArgsLength, char *aArgs[]) { datasetComponents.mIsChannelPresent = true; } + else if (strcmp(aArgs[index], "securitypolicy") == 0) + { + datasetComponents.mIsSecurityPolicyPresent = true; + } else if (strcmp(aArgs[index], "-x") == 0) { uint16_t length; @@ -784,6 +771,119 @@ exit: return error; } +void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy) +{ + mInterpreter.OutputFormat("%d ", aSecurityPolicy.mRotationTime); + + if (aSecurityPolicy.mObtainMasterKeyEnabled) + { + mInterpreter.OutputFormat("o"); + } + + if (aSecurityPolicy.mNativeCommissioningEnabled) + { + mInterpreter.OutputFormat("n"); + } + + if (aSecurityPolicy.mRoutersEnabled) + { + mInterpreter.OutputFormat("r"); + } + + if (aSecurityPolicy.mExternalCommissioningEnabled) + { + mInterpreter.OutputFormat("c"); + } + + if (aSecurityPolicy.mBeaconsEnabled) + { + mInterpreter.OutputFormat("b"); + } + + if (aSecurityPolicy.mCommercialCommissioningEnabled) + { + mInterpreter.OutputFormat("C"); + } + + if (aSecurityPolicy.mAutonomousEnrollmentEnabled) + { + mInterpreter.OutputFormat("e"); + } + + if (aSecurityPolicy.mMasterKeyProvisioningEnabled) + { + mInterpreter.OutputFormat("p"); + } + + if (aSecurityPolicy.mNonCcmRoutersEnabled) + { + mInterpreter.OutputFormat("R"); + } +} + +Error Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, const char *aRotation, const char *aFlags) +{ + Error error; + otSecurityPolicy policy; + + memset(&policy, 0, sizeof(policy)); + SuccessOrExit(error = ParseAsUint16(aRotation, policy.mRotationTime)); + + VerifyOrExit(aFlags != nullptr); + + for (const char *flag = aFlags; *flag != '\0'; flag++) + { + switch (*flag) + { + case 'o': + policy.mObtainMasterKeyEnabled = true; + break; + + case 'n': + policy.mNativeCommissioningEnabled = true; + break; + + case 'r': + policy.mRoutersEnabled = true; + break; + + case 'c': + policy.mExternalCommissioningEnabled = true; + break; + + case 'b': + policy.mBeaconsEnabled = true; + break; + + case 'C': + policy.mCommercialCommissioningEnabled = true; + break; + + case 'e': + policy.mAutonomousEnrollmentEnabled = true; + break; + + case 'p': + policy.mMasterKeyProvisioningEnabled = true; + break; + + case 'R': + policy.mNonCcmRoutersEnabled = true; + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + +exit: + if (error == kErrorNone) + { + aSecurityPolicy = policy; + } + return error; +} + otError Dataset::ProcessSecurityPolicy(uint8_t aArgsLength, char *aArgs[]) { otError error = OT_ERROR_NONE; @@ -792,73 +892,14 @@ otError Dataset::ProcessSecurityPolicy(uint8_t aArgsLength, char *aArgs[]) { if (sDataset.mComponents.mIsSecurityPolicyPresent) { - mInterpreter.OutputFormat("%d ", sDataset.mSecurityPolicy.mRotationTime); - - if (sDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_OBTAIN_MASTER_KEY) - { - mInterpreter.OutputFormat("o"); - } - - if (sDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_NATIVE_COMMISSIONING) - { - mInterpreter.OutputFormat("n"); - } - - if (sDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_ROUTERS) - { - mInterpreter.OutputFormat("r"); - } - - if (sDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER) - { - mInterpreter.OutputFormat("c"); - } - - if (sDataset.mSecurityPolicy.mFlags & OT_SECURITY_POLICY_BEACONS) - { - mInterpreter.OutputFormat("b"); - } - + OutputSecurityPolicy(sDataset.mSecurityPolicy); mInterpreter.OutputLine(""); } } else { - SuccessOrExit(error = ParseAsUint16(aArgs[0], sDataset.mSecurityPolicy.mRotationTime)); - sDataset.mSecurityPolicy.mFlags = 0; - - if (aArgsLength > 1) - { - for (char *arg = aArgs[1]; *arg != '\0'; arg++) - { - switch (*arg) - { - case 'o': - sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_OBTAIN_MASTER_KEY; - break; - - case 'n': - sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_NATIVE_COMMISSIONING; - break; - - case 'r': - sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_ROUTERS; - break; - - case 'c': - sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER; - break; - - case 'b': - sDataset.mSecurityPolicy.mFlags |= OT_SECURITY_POLICY_BEACONS; - break; - - default: - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - } - + SuccessOrExit( + error = ParseSecurityPolicy(sDataset.mSecurityPolicy, aArgs[0], aArgsLength > 1 ? aArgs[1] : nullptr)); sDataset.mComponents.mIsSecurityPolicyPresent = true; } diff --git a/src/cli/cli_dataset.hpp b/src/cli/cli_dataset.hpp index a3c0837e5..1192a2bfb 100644 --- a/src/cli/cli_dataset.hpp +++ b/src/cli/cli_dataset.hpp @@ -105,6 +105,9 @@ private: void HandleDatasetUpdater(otError aError); #endif + void OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy); + Error ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, const char *aRotation, const char *aFlags); + static constexpr Command sCommands[] = { {"active", &Dataset::ProcessActive}, {"activetimestamp", &Dataset::ProcessActiveTimestamp}, diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 43d9d02f9..808deea43 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -931,7 +931,7 @@ TxFrame *Mac::PrepareBeacon(void) beaconPayload = reinterpret_cast(beacon->GetPayload()); - if (Get().IsThreadBeaconEnabled()) + if (Get().GetSecurityPolicy().mBeaconsEnabled) { beaconPayload->Init(); diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 118b1ca5f..697bf1104 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -67,12 +67,11 @@ Error Dataset::Info::GenerateRandom(Instance &aInstance) Clear(); - mActiveTimestamp = 1; - mChannel = preferredChannels.ChooseRandomChannel(); - mChannelMask = supportedChannels.GetMask(); - mSecurityPolicy.mRotationTime = KeyManager::kDefaultKeyRotationTime; - mSecurityPolicy.mFlags = KeyManager::kDefaultSecurityPolicyFlags; - mPanId = Mac::GenerateRandomPanId(); + mActiveTimestamp = 1; + mChannel = preferredChannels.ChooseRandomChannel(); + mChannelMask = supportedChannels.GetMask(); + mPanId = Mac::GenerateRandomPanId(); + static_cast(mSecurityPolicy).SetToDefault(); SuccessOrExit(error = static_cast(mMasterKey).GenerateRandom()); SuccessOrExit(error = static_cast(mPskc).GenerateRandom()); @@ -137,9 +136,7 @@ bool Dataset::Info::IsSubsetOf(const Info &aOther) const if (IsSecurityPolicyPresent()) { - VerifyOrExit(aOther.IsSecurityPolicyPresent() && - GetSecurityPolicy().mRotationTime == aOther.GetSecurityPolicy().mRotationTime && - GetSecurityPolicy().mFlags == aOther.GetSecurityPolicy().mFlags); + VerifyOrExit(aOther.IsSecurityPolicyPresent() && GetSecurityPolicy() == aOther.GetSecurityPolicy()); } if (IsChannelMaskPresent()) @@ -249,7 +246,8 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const case Tlv::kSecurityPolicy: { const SecurityPolicyTlv *tlv = static_cast(cur); - aDatasetInfo.SetSecurityPolicy(tlv->GetRotationTime(), tlv->GetFlags()); + + aDatasetInfo.SetSecurityPolicy(tlv->GetSecurityPolicy()); break; } @@ -363,9 +361,9 @@ Error Dataset::SetFrom(const Info &aDatasetInfo) if (aDatasetInfo.IsSecurityPolicyPresent()) { SecurityPolicyTlv tlv; + tlv.Init(); - tlv.SetRotationTime(aDatasetInfo.GetSecurityPolicy().mRotationTime); - tlv.SetFlags(aDatasetInfo.GetSecurityPolicy().mFlags); + tlv.SetSecurityPolicy(aDatasetInfo.GetSecurityPolicy()); IgnoreError(SetTlv(tlv)); } @@ -593,8 +591,7 @@ Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsMasterKeyUpdated case Tlv::kSecurityPolicy: { const SecurityPolicyTlv *securityPolicy = static_cast(cur); - IgnoreError(keyManager.SetKeyRotation(securityPolicy->GetRotationTime())); - keyManager.SetSecurityPolicyFlags(securityPolicy->GetFlags()); + keyManager.SetSecurityPolicy(securityPolicy->GetSecurityPolicy()); break; } diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index b258e01ce..9c741b265 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -534,20 +534,9 @@ public: * @returns The Security Policy in the Dataset. * */ - const otSecurityPolicy &GetSecurityPolicy(void) const { return mSecurityPolicy; } - - /** - * This method sets the Security Policy in the Dataset. - * - * @param[in] aRotationTime A value for Key Rotation (in units of hours). - * @param[in] aFlags Security policy flags - * - */ - void SetSecurityPolicy(uint16_t aRotationTime, uint8_t aFlags) + const SecurityPolicy &GetSecurityPolicy(void) const { - mSecurityPolicy.mRotationTime = aRotationTime; - mSecurityPolicy.mFlags = aFlags; - mComponents.mIsSecurityPolicyPresent = true; + return static_cast(mSecurityPolicy); } /** @@ -556,7 +545,7 @@ public: * @param[in] aSecurityPolicy A Security Policy to set in Dataset. * */ - void SetSecurityPolicy(const otSecurityPolicy &aSecurityPolicy) + void SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy) { mSecurityPolicy = aSecurityPolicy; mComponents.mIsSecurityPolicyPresent = true; diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 3383f644a..7b1842b04 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -416,7 +416,8 @@ void DatasetManager::SendGetResponse(const Coap::Message & aRequest, { for (const Tlv *cur = dataset.GetTlvsStart(); cur < dataset.GetTlvsEnd(); cur = cur->GetNext()) { - if (cur->GetType() != Tlv::kNetworkMasterKey || Get().IsObtainMasterKeyEnabled()) + if (cur->GetType() != Tlv::kNetworkMasterKey || + Get().GetSecurityPolicy().mObtainMasterKeyEnabled) { SuccessOrExit(error = cur->AppendTo(*message)); } @@ -428,7 +429,8 @@ void DatasetManager::SendGetResponse(const Coap::Message & aRequest, { const Tlv *tlv; - if (aTlvs[index] == Tlv::kNetworkMasterKey && !Get().IsObtainMasterKeyEnabled()) + if (aTlvs[index] == Tlv::kNetworkMasterKey && + !Get().GetSecurityPolicy().mObtainMasterKeyEnabled) { continue; } diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index a612dda99..c53e3fcf2 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -387,9 +387,9 @@ Error ActiveDataset::GenerateLocal(void) if (dataset.GetTlv() == nullptr) { SecurityPolicyTlv tlv; + tlv.Init(); - tlv.SetRotationTime(static_cast(Get().GetKeyRotation())); - tlv.SetFlags(Get().GetSecurityPolicyFlags()); + tlv.SetSecurityPolicy(Get().GetSecurityPolicy()); IgnoreError(dataset.SetTlv(tlv)); } diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 0c40ed1f6..5acd92f0f 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -145,6 +145,33 @@ void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength()); } +bool SecurityPolicyTlv::IsValid(void) const +{ + return GetLength() >= sizeof(mRotationTime) && GetRotationTime() >= SecurityPolicy::kMinKeyRotationTime && + GetFlagsLength() >= kThread11FlagsLength; +} + +SecurityPolicy SecurityPolicyTlv::GetSecurityPolicy(void) const +{ + OT_ASSERT(IsValid()); + + SecurityPolicy securityPolicy; + uint8_t length = OT_MIN(static_cast(sizeof(mFlags)), GetFlagsLength()); + + securityPolicy.mRotationTime = GetRotationTime(); + securityPolicy.SetFlags(mFlags, length); + + return securityPolicy; +} + +void SecurityPolicyTlv::SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy) +{ + SetRotationTime(aSecurityPolicy.mRotationTime); + aSecurityPolicy.GetFlags(mFlags, sizeof(mFlags)); + + OT_ASSERT(IsValid()); +} + bool ChannelTlv::IsValid(void) const { bool ret = false; diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 96d621530..b45129dd2 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -971,52 +971,41 @@ public: * @retval FALSE If the TLV does not appear to be well-formed. * */ - bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); } + bool IsValid(void) const; /** - * This method returns the Rotation Time value. + * This method returns the Security Policy. * - * @returns The Rotation Time value. + * @returns The Security Policy. * */ - uint16_t GetRotationTime(void) const { return HostSwap16(mRotationTime); } + SecurityPolicy GetSecurityPolicy(void) const; /** - * This method sets the Rotation Time value. + * This method sets the Security Policy. * - * @param[in] aRotationTime The Rotation Time value. + * @param[in] aSecurityPolicy The Security Policy which will be set. * */ - void SetRotationTime(uint16_t aRotationTime) { mRotationTime = HostSwap16(aRotationTime); } - - enum - { - kObtainMasterKeyFlag = OT_SECURITY_POLICY_OBTAIN_MASTER_KEY, ///< Obtaining the Master Key - kNativeCommissioningFlag = OT_SECURITY_POLICY_NATIVE_COMMISSIONING, ///< Native Commissioning - kRoutersFlag = OT_SECURITY_POLICY_ROUTERS, ///< Routers enabled - kExternalCommissionerFlag = OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER, ///< External Commissioner allowed - kBeaconsFlag = OT_SECURITY_POLICY_BEACONS, ///< Beacons enabled - }; - - /** - * This method returns the Flags value. - * - * @returns The Flags value. - * - */ - uint8_t GetFlags(void) const { return mFlags; } - - /** - * This method sets the Flags value. - * - * @param[in] aFlags The Flags value. - * - */ - void SetFlags(uint8_t aFlags) { mFlags = aFlags; } + void SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy); private: + enum : uint8_t + { + kThread11FlagsLength = 1, ///< The Thread 1.1 Security Policy Flags length. + kThread12FlagsLength = 2, ///< The Thread 1.2 Security Policy Flags length. + }; + + void SetRotationTime(uint16_t aRotationTime) { mRotationTime = HostSwap16(aRotationTime); } + uint16_t GetRotationTime(void) const { return HostSwap16(mRotationTime); } + uint8_t GetFlagsLength(void) const { return GetLength() - sizeof(mRotationTime); } + uint16_t mRotationTime; - uint8_t mFlags; +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + uint8_t mFlags[kThread12FlagsLength]; +#else + uint8_t mFlags[kThread11FlagsLength]; +#endif } OT_TOOL_PACKED_END; /** diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index fdbe80655..9e0b93470 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -56,6 +56,116 @@ const uint8_t KeyManager::kTrelInfoString[] = {'T', 'h', 'r', 'e', 'a', 'd', 'O' 'r', 'I', 'n', 'f', 'r', 'a', 'K', 'e', 'y'}; #endif +void SecurityPolicy::SetToDefault(void) +{ + mRotationTime = kDefaultKeyRotationTime; + SetToDefaultFlags(); +} + +void SecurityPolicy::SetToDefaultFlags(void) +{ + mObtainMasterKeyEnabled = true; + mNativeCommissioningEnabled = true; + mRoutersEnabled = true; + mExternalCommissioningEnabled = true; + mBeaconsEnabled = true; + mCommercialCommissioningEnabled = false; + mAutonomousEnrollmentEnabled = false; + mMasterKeyProvisioningEnabled = false; + mTobleLinkEnabled = true; + mNonCcmRoutersEnabled = false; + mVersionThresholdForRouting = 0; +} + +void SecurityPolicy::SetFlags(const uint8_t *aFlags, uint8_t aFlagsLength) +{ + OT_ASSERT(aFlagsLength > 0); + + SetToDefaultFlags(); + + mObtainMasterKeyEnabled = aFlags[0] & kObtainMasterKeyMask; + mNativeCommissioningEnabled = aFlags[0] & kNativeCommissioningMask; + mRoutersEnabled = aFlags[0] & kRoutersMask; + mExternalCommissioningEnabled = aFlags[0] & kExternalCommissioningMask; + mBeaconsEnabled = aFlags[0] & kBeaconsMask; + mCommercialCommissioningEnabled = (aFlags[0] & kCommercialCommissioningMask) == 0; + mAutonomousEnrollmentEnabled = (aFlags[0] & kAutonomousEnrollmentMask) == 0; + mMasterKeyProvisioningEnabled = (aFlags[0] & kMasterKeyProvisioningMask) == 0; + + VerifyOrExit(aFlagsLength > sizeof(aFlags[0])); + mTobleLinkEnabled = aFlags[1] & kTobleLinkMask; + mNonCcmRoutersEnabled = (aFlags[1] & kNonCcmRoutersMask) == 0; + mVersionThresholdForRouting = aFlags[1] & kVersionThresholdForRoutingMask; + +exit: + return; +} + +void SecurityPolicy::GetFlags(uint8_t *aFlags, uint8_t aFlagsLength) const +{ + OT_ASSERT(aFlagsLength > 0); + + memset(aFlags, 0, aFlagsLength); + + if (mObtainMasterKeyEnabled) + { + aFlags[0] |= kObtainMasterKeyMask; + } + + if (mNativeCommissioningEnabled) + { + aFlags[0] |= kNativeCommissioningMask; + } + + if (mRoutersEnabled) + { + aFlags[0] |= kRoutersMask; + } + + if (mExternalCommissioningEnabled) + { + aFlags[0] |= kExternalCommissioningMask; + } + + if (mBeaconsEnabled) + { + aFlags[0] |= kBeaconsMask; + } + + if (!mCommercialCommissioningEnabled) + { + aFlags[0] |= kCommercialCommissioningMask; + } + + if (!mAutonomousEnrollmentEnabled) + { + aFlags[0] |= kAutonomousEnrollmentMask; + } + + if (!mMasterKeyProvisioningEnabled) + { + aFlags[0] |= kMasterKeyProvisioningMask; + } + + VerifyOrExit(aFlagsLength > sizeof(aFlags[0])); + + if (mTobleLinkEnabled) + { + aFlags[1] |= kTobleLinkMask; + } + + if (!mNonCcmRoutersEnabled) + { + aFlags[1] |= kNonCcmRoutersMask; + } + + aFlags[1] |= kReservedMask; + aFlags[1] |= mVersionThresholdForRouting; + +exit: + return; +} + KeyManager::KeyManager(Instance &aInstance) : InstanceLocator(aInstance) , mKeySequence(0) @@ -63,12 +173,10 @@ KeyManager::KeyManager(Instance &aInstance) , mStoredMacFrameCounter(0) , mStoredMleFrameCounter(0) , mHoursSinceKeyRotation(0) - , mKeyRotationTime(kDefaultKeyRotationTime) , mKeySwitchGuardTime(kDefaultKeySwitchGuardTime) , mKeySwitchGuardEnabled(false) , mKeyRotationTimer(aInstance, KeyManager::HandleKeyRotationTimer) , mKekFrameCounter(0) - , mSecurityPolicyFlags(kDefaultSecurityPolicyFlags) , mIsPskcSet(false) { Error error = mMasterKey.GenerateRandom(); @@ -298,21 +406,11 @@ void KeyManager::SetKek(const uint8_t *aKek) mKekFrameCounter = 0; } -Error KeyManager::SetKeyRotation(uint32_t aKeyRotation) +void KeyManager::SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy) { - Error result = kErrorNone; + OT_ASSERT(aSecurityPolicy.mRotationTime >= SecurityPolicy::kMinKeyRotationTime); - VerifyOrExit(aKeyRotation >= static_cast(kMinKeyRotationTime), result = kErrorInvalidArgs); - - mKeyRotationTime = aKeyRotation; - -exit: - return result; -} - -void KeyManager::SetSecurityPolicyFlags(uint8_t aSecurityPolicyFlags) -{ - IgnoreError(Get().Update(mSecurityPolicyFlags, aSecurityPolicyFlags, kEventSecurityPolicyChanged)); + IgnoreError(Get().Update(mSecurityPolicy, aSecurityPolicy, kEventSecurityPolicyChanged)); } void KeyManager::StartKeyRotationTimer(void) @@ -339,7 +437,7 @@ void KeyManager::HandleKeyRotationTimer(void) mKeyRotationTimer.StartAt(mKeyRotationTimer.GetFireTime(), kOneHourIntervalInMsec); - if (mHoursSinceKeyRotation >= mKeyRotationTime) + if (mHoursSinceKeyRotation >= mSecurityPolicy.mRotationTime) { SetCurrentKeySequence(mKeySequence + 1); } diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index 9e661ff83..6c9b942d7 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -41,6 +41,7 @@ #include #include "common/clearable.hpp" +#include "common/encoding.hpp" #include "common/equatable.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" @@ -61,6 +62,72 @@ namespace ot { * @{ */ +/** + * This class represents Security Policy Rotation and Flags. + * + */ +class SecurityPolicy : public otSecurityPolicy, public Equatable +{ +public: + enum : uint16_t + { + kMinKeyRotationTime = 1, ///< The minimum Key Rotation Time in hours. + kDefaultKeyRotationTime = 672, ///< Default Key Rotation Time (in unit of hours). + }; + + /** + * This constructor initializes the object with default Key Rotation Time + * and Security Policy Flags. + * + */ + SecurityPolicy(void) { SetToDefault(); } + + /** + * This method sets the Security Policy to default values. + * + */ + void SetToDefault(void); + + /** + * This method sets the Security Policy Flags. + * + * @param[in] aFlags The Security Policy Flags. + * @param[in] aFlagsLength The length of the Security Policy Flags, 1 byte for + * Thread 1.1 devices, and 2 bytes for Thread 1.2 or higher. + * + */ + void SetFlags(const uint8_t *aFlags, uint8_t aFlagsLength); + + /** + * This method returns the Security Policy Flags. + * + * @param[out] aFlags A pointer to the Security Policy Flags buffer. + * @param[in] aFlagsLength The length of the Security Policy Flags buffer. + * + */ + void GetFlags(uint8_t *aFlags, uint8_t aFlagsLength) const; + +private: + enum : uint8_t + { + kDefaultFlags = 0xff, + kObtainMasterKeyMask = 1 << 7, + kNativeCommissioningMask = 1 << 6, + kRoutersMask = 1 << 5, + kExternalCommissioningMask = 1 << 4, + kBeaconsMask = 1 << 3, + kCommercialCommissioningMask = 1 << 2, + kAutonomousEnrollmentMask = 1 << 1, + kMasterKeyProvisioningMask = 1 << 0, + kTobleLinkMask = 1 << 7, + kNonCcmRoutersMask = 1 << 6, + kReservedMask = 0x38, + kVersionThresholdForRoutingMask = 0x07, + }; + + void SetToDefaultFlags(void); +}; + /** * This class represents a Thread Master Key. * @@ -115,16 +182,6 @@ typedef Mac::Key Kek; class KeyManager : public InstanceLocator, private NonCopyable { public: - enum : uint16_t - { - kDefaultKeyRotationTime = 672, ///< Default Key Rotation Time (in unit of hours). - }; - - enum : uint8_t - { - kDefaultSecurityPolicyFlags = 0xff, ///< Default Security Policy Flags. - }; - /** * This constructor initializes the object. * @@ -365,29 +422,6 @@ public: */ void IncrementKekFrameCounter(void) { mKekFrameCounter++; } - /** - * This method returns the KeyRotation time. - * - * The KeyRotation time is the time interval after witch security key will be automatically rotated. - * - * @returns The KeyRotation value in hours. - */ - uint32_t GetKeyRotation(void) const { return mKeyRotationTime; } - - /** - * This method sets the KeyRotation time. - * - * The KeyRotation time is the time interval after witch security key will be automatically rotated. - * Its value shall be larger than or equal to kMinKeyRotationTime. - * - * @param[in] aKeyRotation The KeyRotation value in hours. - * - * @retval kErrorNone KeyRotation time updated. - * @retval kErrorInvalidArgs @p aKeyRotation is out of range. - * - */ - Error SetKeyRotation(uint32_t aKeyRotation); - /** * This method returns the KeySwitchGuardTime. * @@ -409,82 +443,26 @@ public: void SetKeySwitchGuardTime(uint32_t aKeySwitchGuardTime) { mKeySwitchGuardTime = aKeySwitchGuardTime; } /** - * This method returns the Security Policy Flags. + * This method returns the Security Policy. * - * The Security Policy Flags specifies network administrator preferences for which - * security-related operations are allowed or disallowed. + * The Security Policy specifies Key Rotation Time and network administrator preferences + * for which security-related operations are allowed or disallowed. * - * @returns The SecurityPolicy Flags. + * @returns The SecurityPolicy. * */ - uint8_t GetSecurityPolicyFlags(void) const { return mSecurityPolicyFlags; } + const SecurityPolicy &GetSecurityPolicy(void) const { return mSecurityPolicy; } /** - * This method sets the Security Policy Flags. + * This method sets the Security Policy. * - * The Security Policy Flags specifies network administrator preferences for which - * security-related operations are allowed or disallowed. + * The Security Policy specifies Key Rotation Time and network administrator preferences + * for which security-related operations are allowed or disallowed. * - * @param[in] aSecurityPolicyFlags The Security Policy Flags. + * @param[in] aSecurityPolicy The Security Policy. * */ - void SetSecurityPolicyFlags(uint8_t aSecurityPolicyFlags); - - /** - * This method indicates whether or not obtaining Master key for out-of-band is enabled. - * - * @retval TRUE If obtaining Master key for out-of-band is enabled. - * @retval FALSE If obtaining Master key for out-of-band is not enabled. - * - */ - bool IsObtainMasterKeyEnabled(void) const - { - return (mSecurityPolicyFlags & OT_SECURITY_POLICY_OBTAIN_MASTER_KEY) != 0; - } - - /** - * This method indicates whether or not Native Commissioning using PSKc is allowed. - * - * @retval TRUE If Native Commissioning using PSKc is allowed. - * @retval FALSE If Native Commissioning using PSKc is not allowed. - * - */ - bool IsNativeCommissioningAllowed(void) const - { - return (mSecurityPolicyFlags & OT_SECURITY_POLICY_NATIVE_COMMISSIONING) != 0; - } - - /** - * This method indicates whether or not Thread 1.1 Routers are enabled. - * - * @retval TRUE If Thread 1.1 Routers are enabled. - * @retval FALSE If Thread 1.1 Routers are not enabled. - * - */ - bool IsRouterEnabled(void) const { return (mSecurityPolicyFlags & OT_SECURITY_POLICY_ROUTERS) != 0; } - - /** - * This method indicates whether or not external Commissioner authentication is allowed using PSKc. - * - * @retval TRUE If the commissioning sessions by an external Commissioner based on the PSKc are allowed - * to be established and that changes to the Commissioner Dataset by on-mesh nodes are allowed. - * @retval FALSE If the commissioning sessions by an external Commissioner based on the PSKc are not allowed - * to be established and that changes to the Commissioner Dataset by on-mesh nodes are not allowed. - * - */ - bool IsExternalCommissionerAllowed(void) const - { - return (mSecurityPolicyFlags & OT_SECURITY_POLICY_EXTERNAL_COMMISSIONER) != 0; - } - - /** - * This method indicates whether or not Thread Beacons are enabled. - * - * @retval TRUE If Thread Beacons are enabled. - * @retval FALSE If Thread Beacons are not enabled. - * - */ - bool IsThreadBeaconEnabled(void) const { return (mSecurityPolicyFlags & OT_SECURITY_POLICY_BEACONS) != 0; } + void SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy); /** * This method updates the MAC keys and MLE key. @@ -503,7 +481,6 @@ public: private: enum { - kMinKeyRotationTime = 1, kDefaultKeySwitchGuardTime = 624, kOneHourIntervalInMsec = 3600u * 1000u, }; @@ -555,7 +532,6 @@ private: uint32_t mStoredMleFrameCounter; uint32_t mHoursSinceKeyRotation; - uint32_t mKeyRotationTime; uint32_t mKeySwitchGuardTime; bool mKeySwitchGuardEnabled; TimerMilli mKeyRotationTimer; @@ -566,8 +542,8 @@ private: Kek mKek; uint32_t mKekFrameCounter; - uint8_t mSecurityPolicyFlags; - bool mIsPskcSet : 1; + SecurityPolicy mSecurityPolicy; + bool mIsPskcSet : 1; }; /** diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 1b6e6d47d..9acd1d262 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1584,7 +1584,7 @@ void Mle::HandleNotifierEvents(Events aEvents) if (aEvents.Contains(kEventSecurityPolicyChanged)) { - Get().AllowNativeCommissioner(Get().IsNativeCommissioningAllowed()); + Get().AllowNativeCommissioner(Get().GetSecurityPolicy().mNativeCommissioningEnabled); } exit: diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index d6fe84b18..250e165e8 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2907,7 +2907,7 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M discoveryResponse.Init(); discoveryResponse.SetVersion(kThreadVersion); - if (Get().IsNativeCommissioningAllowed()) + if (Get().GetSecurityPolicy().mNativeCommissioningEnabled) { SuccessOrExit(error = Tlv::Append(*message, MeshCoP::kBorderAgentUdpPort)); diff --git a/src/lib/spinel/radio_spinel_impl.hpp b/src/lib/spinel/radio_spinel_impl.hpp index 612443bb7..246b7b92a 100644 --- a/src/lib/spinel/radio_spinel_impl.hpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -52,6 +52,7 @@ #include "meshcop/dataset.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "radio/radio.hpp" +#include "thread/key_manager.hpp" #ifndef MS_PER_S #define MS_PER_S 1000 @@ -699,8 +700,17 @@ otError RadioSpinel::ThreadDatasetHandler(con case SPINEL_PROP_DATASET_SECURITY_POLICY: { + uint8_t flags[2]; + uint8_t flagsLength = 1; + SuccessOrExit(error = decoder.ReadUint16(opDataset.mSecurityPolicy.mRotationTime)); - SuccessOrExit(error = decoder.ReadUint8(opDataset.mSecurityPolicy.mFlags)); + SuccessOrExit(error = decoder.ReadUint8(flags[0])); + if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2 && decoder.GetRemainingLengthInStruct() > 0) + { + SuccessOrExit(error = decoder.ReadUint8(flags[1])); + ++flagsLength; + } + static_cast(opDataset.mSecurityPolicy).SetFlags(flags, flagsLength); opDataset.mComponents.mIsSecurityPolicyPresent = true; break; } diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 91c192793..4814ef314 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -2783,7 +2783,7 @@ enum SPINEL_PROP_DATASET_DELAY_TIMER = SPINEL_PROP_THREAD_EXT__BEGIN + 30, /// Operational Dataset Security Policy - /** Format: `SC` - No direct read or write + /** Format: `SD` - No direct read or write * * It can only be included in one of the Dataset related properties below: * @@ -2797,6 +2797,8 @@ enum * Content is * `S` : Key Rotation Time (in units of hour) * `C` : Security Policy Flags (as specified in Thread 1.1 Section 8.10.1.15) + * `C` : Optional Security Policy Flags extension (as specified in Thread 1.2 Section 8.10.1.15). + * 0xf8 is used if this field is missing. * */ SPINEL_PROP_DATASET_SECURITY_POLICY = SPINEL_PROP_THREAD_EXT__BEGIN + 31, diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index f4f9d9ac3..9e0a7453c 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -1343,10 +1343,17 @@ otError NcpBase::EncodeOperationalDataset(const otOperationalDataset &aDataset) if (aDataset.mComponents.mIsSecurityPolicyPresent) { + uint8_t flags[2]; + + static_cast(aDataset.mSecurityPolicy).GetFlags(flags, sizeof(flags)); SuccessOrExit(error = mEncoder.OpenStruct()); SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_SECURITY_POLICY)); SuccessOrExit(error = mEncoder.WriteUint16(aDataset.mSecurityPolicy.mRotationTime)); - SuccessOrExit(error = mEncoder.WriteUint8(aDataset.mSecurityPolicy.mFlags)); + SuccessOrExit(error = mEncoder.WriteUint8(flags[0])); + if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2) + { + SuccessOrExit(error = mEncoder.WriteUint8(flags[1])); + } SuccessOrExit(error = mEncoder.CloseStruct()); } @@ -1546,8 +1553,17 @@ otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset, if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) { + uint8_t flags[2]; + uint8_t flagsLength = 1; + SuccessOrExit(error = mDecoder.ReadUint16(aDataset.mSecurityPolicy.mRotationTime)); - SuccessOrExit(error = mDecoder.ReadUint8(aDataset.mSecurityPolicy.mFlags)); + SuccessOrExit(error = mDecoder.ReadUint8(flags[0])); + if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2 && mDecoder.GetRemainingLengthInStruct() > 0) + { + SuccessOrExit(error = mDecoder.ReadUint8(flags[1])); + ++flagsLength; + } + static_cast(aDataset.mSecurityPolicy).SetFlags(flags, flagsLength); } aDataset.mComponents.mIsSecurityPolicyPresent = true; diff --git a/tests/scripts/thread-cert/Cert_5_8_04_SecurityPolicyTLV.py b/tests/scripts/thread-cert/Cert_5_8_04_SecurityPolicyTLV.py index 16842e7e1..b9b8c4022 100755 --- a/tests/scripts/thread-cert/Cert_5_8_04_SecurityPolicyTLV.py +++ b/tests/scripts/thread-cert/Cert_5_8_04_SecurityPolicyTLV.py @@ -137,7 +137,7 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): # Disabling O-Bit security_policy = [3600, 0b01111000] self.nodes[COMMISSIONER_1].send_mgmt_active_set( active_timestamp=15, - binary='0c030e1078', + security_policy=[3600, 'nrcb'], ) self.simulator.go(5) @@ -148,10 +148,9 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): # Step 9 # Disabling N-Bit security_policy = [3600, 0b10111000] - self.nodes[COMMISSIONER_1].send_mgmt_active_set( active_timestamp=20, - binary='0c030e10b8', + security_policy=[3600, 'orcb'], ) self.simulator.go(5) @@ -166,7 +165,7 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): # Disabling B-Bit security_policy = [3600, 0b11110000] self.nodes[COMMISSIONER_1].send_mgmt_active_set( active_timestamp=25, - binary='0c030e10f0', + security_policy=[3600, 'onrc'], ) self.simulator.go(5) @@ -181,7 +180,7 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): # Disabling R-Bit security_policy = [3600, 0b11011000] self.nodes[COMMISSIONER_1].send_mgmt_active_set( active_timestamp=30, - binary='0c030e10d8', + security_policy=[3600, 'oncb'], ) self.simulator.go(5) @@ -218,7 +217,13 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): pkts.filter_wpan_src64(LEADER).\ filter_ipv6_dst(COMMISSIONER_1_RLOC).\ filter_coap_ack(MGMT_ACTIVE_GET_URI).\ - filter(lambda p: p.thread_meshcop.tlv.unknown == '0e10f8').\ + filter(lambda p: (p.thread_meshcop.tlv.sec_policy_rot == 3600 and + p.thread_meshcop.tlv.sec_policy_o == 1 and + p.thread_meshcop.tlv.sec_policy_n == 1 and + p.thread_meshcop.tlv.sec_policy_r == 1 and + p.thread_meshcop.tlv.sec_policy_c == 1 and + p.thread_meshcop.tlv.sec_policy_b == 1) or + (p.thread_meshcop.tlv.unknown == '0e10ff')).\ must_next() # Step 5: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader @@ -237,7 +242,8 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): NM_SECURITY_POLICY_TLV } == set(p.thread_meshcop.tlv.type) and\ p.thread_meshcop.tlv.active_tstamp == 15 and\ - p.thread_meshcop.tlv.unknown == '0e1078').\ + (p.thread_meshcop.tlv.sec_policy_o == 0 or + p.thread_meshcop.tlv.unknown == '0e107f')).\ must_next() # Step 6: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 @@ -289,7 +295,8 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): NM_SECURITY_POLICY_TLV } == set(p.thread_meshcop.tlv.type) and\ p.thread_meshcop.tlv.active_tstamp == 20 and\ - p.thread_meshcop.tlv.unknown == '0e10b8').\ + (p.thread_meshcop.tlv.sec_policy_n == 0 or + p.thread_meshcop.tlv.unknown == '0e10bf')).\ must_next() # Step 10: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 @@ -326,7 +333,8 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): NM_SECURITY_POLICY_TLV } == set(p.thread_meshcop.tlv.type) and\ p.thread_meshcop.tlv.active_tstamp == 25 and\ - p.thread_meshcop.tlv.unknown == '0e10f0').\ + (p.thread_meshcop.tlv.sec_policy_b == 0 or + p.thread_meshcop.tlv.unknown == '0e10f7')).\ must_next() # Step 14: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 @@ -371,7 +379,8 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): NM_SECURITY_POLICY_TLV } == set(p.thread_meshcop.tlv.type) and\ p.thread_meshcop.tlv.active_tstamp == 30 and\ - p.thread_meshcop.tlv.unknown == '0e10d8').\ + (p.thread_meshcop.tlv.sec_policy_r == 0 or + p.thread_meshcop.tlv.unknown == '0e10df')).\ must_next() # Step 18: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1 @@ -401,7 +410,8 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase): filter_mle_cmd(MLE_DATA_RESPONSE).\ filter(lambda p: p.mle.tlv.active_tstamp == 30 and\ - p.thread_meshcop.tlv.unknown == '0e10d8').\ + (p.thread_meshcop.tlv.sec_policy_r == 0 or + p.thread_meshcop.tlv.unknown == '0e10df')).\ must_next() diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index d84716fd0..9f287146b 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1927,6 +1927,7 @@ class NodeImpl: master_key=None, mesh_local=None, network_name=None, + security_policy=None, binary=None, ): cmd = 'dataset mgmtsetcommand active ' @@ -1955,6 +1956,10 @@ class NodeImpl: if network_name is not None: cmd += 'networkname %s ' % self._escape_escapable(network_name) + if security_policy is not None: + rotation, flags = security_policy + cmd += 'securitypolicy %d %s ' % (rotation, flags) + if binary is not None: cmd += '-x %s ' % binary diff --git a/tools/otci/otci/otci.py b/tools/otci/otci/otci.py index 08a118df3..53ac63ca7 100644 --- a/tools/otci/otci/otci.py +++ b/tools/otci/otci/otci.py @@ -1287,7 +1287,7 @@ class OTCI(object): elif key == 'PSKc': dataset['pskc'] = val elif key == 'Security Policy': - rotation_time, flags = val.split(', ') + rotation_time, flags = val.split(' ') rotation_time = int(rotation_time) dataset['security_policy'] = SecurityPolicy(rotation_time, flags) else: