/* * * Copyright (c) 2020-2021 Project CHIP Authors * Copyright (c) 2016-2017 Nest Labs, Inc. * * 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. */ #include #include namespace chip { /** * Determine whether the specified key ID belongs to one of the application * group key types (static or rotating). * * @param[in] keyId CHIP key identifier. * @return true if the keyId is of rotating or static key type. * */ bool ChipKeyId::IsAppGroupKey(uint32_t keyId) { return IsAppStaticKey(keyId) || IsAppRotatingKey(keyId); } /** * Determine whether the specified application group key ID uses "current" epoch key. * * @param[in] keyId CHIP application group key identifier. * @return true if the keyId indicates usage of the current epoch key. * */ bool ChipKeyId::UsesCurrentEpochKey(uint32_t keyId) { return IncorporatesEpochKey(keyId) && ((keyId & kFlag_UseCurrentEpochKey) != 0); } /** * Determine whether the specified application group key ID incorporates root key. * * @param[in] keyId CHIP application group key identifier. * @return true if the keyId incorporates root key. * */ bool ChipKeyId::IncorporatesRootKey(uint32_t keyId) { uint32_t keyType = GetType(keyId); return keyType == kType_AppStaticKey || keyType == kType_AppRotatingKey || keyType == kType_AppRootKey || keyType == kType_AppIntermediateKey; } /** * Determine whether the specified application group key ID incorporates group master key. * * @param[in] keyId CHIP application group key identifier. * @return true if the keyId incorporates group master key. * */ bool ChipKeyId::IncorporatesAppGroupMasterKey(uint32_t keyId) { uint32_t keyType = GetType(keyId); return keyType == kType_AppStaticKey || keyType == kType_AppRotatingKey || keyType == kType_AppGroupMasterKey; } /** * Construct application group key ID given constituent key IDs and other information. * * @param[in] keyType Derived application group key type. * @param[in] rootKeyId Root key ID used to derive application group key. * @param[in] epochKeyId Epoch key ID used to derive application group key. * @param[in] appGroupMasterKeyId Application group master key ID used to derive * application group key. * @param[in] useCurrentEpochKey A boolean flag that indicates if key should be derived * using "current" epoch key. * @return application group key ID. * */ uint32_t ChipKeyId::MakeAppKeyId(uint32_t keyType, uint32_t rootKeyId, uint32_t epochKeyId, uint32_t appGroupMasterKeyId, bool useCurrentEpochKey) { return (keyType | (rootKeyId & kMask_RootKeyNumber) | (appGroupMasterKeyId & kMask_GroupLocalNumber) | (useCurrentEpochKey ? static_cast(kFlag_UseCurrentEpochKey) : (epochKeyId & kMask_EpochKeyNumber))); } /** * Construct application intermediate key ID given constituent key IDs. * * @param[in] rootKeyId Root key ID used to derive application intermediate key. * @param[in] epochKeyId Epoch key ID used to derive application intermediate key. * @param[in] useCurrentEpochKey A boolean flag that indicates if key should be derived * using "current" epoch key. * @return application intermediate key ID. * */ uint32_t ChipKeyId::MakeAppIntermediateKeyId(uint32_t rootKeyId, uint32_t epochKeyId, bool useCurrentEpochKey) { return MakeAppKeyId(kType_AppIntermediateKey, rootKeyId, epochKeyId, kNone, useCurrentEpochKey); } /** * Construct application rotating key ID given constituent key IDs and other information. * * @param[in] rootKeyId Root key ID used to derive application rotating key. * @param[in] epochKeyId Epoch key ID used to derive application rotating key. * @param[in] appGroupMasterKeyId Application group master key ID used to derive * application rotating key. * @param[in] useCurrentEpochKey A boolean flag that indicates if key should be derived * using "current" epoch key. * @return application rotating key ID. * */ uint32_t ChipKeyId::MakeAppRotatingKeyId(uint32_t rootKeyId, uint32_t epochKeyId, uint32_t appGroupMasterKeyId, bool useCurrentEpochKey) { return MakeAppKeyId(kType_AppRotatingKey, rootKeyId, epochKeyId, appGroupMasterKeyId, useCurrentEpochKey); } /** * Construct application static key ID given constituent key IDs. * * @param[in] rootKeyId Root key ID used to derive application static key. * @param[in] appGroupMasterKeyId Application group master key ID used to derive * application static key. * @return application static key ID. * */ uint32_t ChipKeyId::MakeAppStaticKeyId(uint32_t rootKeyId, uint32_t appGroupMasterKeyId) { return MakeAppKeyId(kType_AppStaticKey, rootKeyId, kNone, appGroupMasterKeyId, false); } /** * Convert application key ID to application static key ID. * * @param[in] keyId Application key ID. * @return application static key ID. * */ uint32_t ChipKeyId::ConvertToStaticAppKeyId(uint32_t keyId) { return MakeAppStaticKeyId(GetRootKeyId(keyId), GetAppGroupMasterKeyId(keyId)); } /** * Update application group key ID with new epoch key number. * * @param[in] keyId Application key ID. * @param[in] epochKeyId Epoch key ID, which will be used in construction * of the updated application key ID. * @return application key ID. * */ uint32_t ChipKeyId::UpdateEpochKeyId(uint32_t keyId, uint32_t epochKeyId) { return (keyId & ~(kFlag_UseCurrentEpochKey | kMask_EpochKeyNumber)) | (epochKeyId & kMask_EpochKeyNumber); } /** * Determine whether key identifier has valid (legal) value. * * @param[in] keyId CHIP key ID. * @return true if key ID value is valid. * */ bool ChipKeyId::IsValidKeyId(uint32_t keyId) { unsigned int usedBits = kMask_KeyType; switch (GetType(keyId)) { case kType_None: return false; case kType_General: case kType_Session: usedBits |= kMask_KeyNumber; break; case kType_AppStaticKey: usedBits |= kMask_RootKeyNumber | kMask_GroupLocalNumber; break; case kType_AppRotatingKey: usedBits |= kFlag_UseCurrentEpochKey | kMask_RootKeyNumber | kMask_GroupLocalNumber; if (!UsesCurrentEpochKey(keyId)) { usedBits |= kMask_EpochKeyNumber; } break; case kType_AppRootKey: usedBits |= kMask_RootKeyNumber; break; case kType_AppIntermediateKey: usedBits |= kFlag_UseCurrentEpochKey | kMask_RootKeyNumber; if (!UsesCurrentEpochKey(keyId)) { usedBits |= kMask_EpochKeyNumber; } break; case kType_AppEpochKey: usedBits |= kFlag_UseCurrentEpochKey; if (!UsesCurrentEpochKey(keyId)) { usedBits |= kMask_EpochKeyNumber; } break; case kType_AppGroupMasterKey: usedBits |= kMask_GroupLocalNumber; break; default: return false; } if (IncorporatesRootKey(keyId)) { uint32_t rootKeyId = GetRootKeyId(keyId); VerifyOrReturnError(rootKeyId == kFabricRootKey || rootKeyId == kClientRootKey || rootKeyId == kServiceRootKey, false); } return (keyId & ~usedBits) == 0; } /** * Determine whether a given key ID identifies a key that is suitable for CHIP message encryption. * * @param[in] keyId CHIP key ID. * @param[in] allowLogicalKeys Specifies whether logical keys IDs (such as the "current" rotating key) * should be considered suitable for message encryption. * @return true If the identified key can be used to encrypt CHIP messages. * */ bool ChipKeyId::IsMessageSessionId(uint32_t keyId, bool allowLogicalKeys) { switch (GetType(keyId)) { case kType_Session: case kType_AppStaticKey: return true; case kType_AppRotatingKey: return allowLogicalKeys || !UsesCurrentEpochKey(keyId); default: return false; } } /** * Determines whether two key IDs identify the same key, or in the case of rotating keys, the same * group of keys independent of any particular epoch. * * @param[in] keyId1 The first key ID to test. * @param[in] keyId2 The second key ID to test. * * @return True if the keys IDs represent the same key. */ bool ChipKeyId::IsSameKeyOrGroup(uint32_t keyId1, uint32_t keyId2) { enum { kIgnoreEpochMask = ~(kMask_EpochKeyNumber | kFlag_UseCurrentEpochKey) }; // If the key ids are identical then they represent the same key. if (keyId1 == keyId2) return true; // For rotating keys, treat the key ids as the same if they differ only in their choice of epoch // key number. if (IncorporatesEpochKey(keyId1) && !IsAppEpochKey(keyId1) && (keyId1 & kIgnoreEpochMask) == (keyId2 & kIgnoreEpochMask)) return true; // Otherwise the key ids identify different keys. return false; } /** * Decode a CHIP key identifier with a descriptive string. * * @param[in] keyId CHIP key ID to decode and for which to return * a descriptive string. * * @return A pointer to a NULL-terminated string describing the specified key ID. * */ const char * ChipKeyId::DescribeKey(uint32_t keyId) { const char * retval; switch (GetType(keyId)) { case kType_None: retval = "No Key"; break; case kType_General: if (keyId == kFabricSecret) { retval = "Fabric Secret"; } else { retval = "Other General Key"; } break; case kType_Session: retval = "Session Key"; break; case kType_AppStaticKey: retval = "Application Static Key"; break; case kType_AppRotatingKey: retval = "Application Rotating Key"; break; case kType_AppRootKey: if (keyId == kFabricRootKey) { retval = "Fabric Root Key"; } else if (keyId == kClientRootKey) { retval = "Client Root Key"; } else if (keyId == kServiceRootKey) { retval = "Service Root Key"; } else { retval = "Other Root Key"; } break; case kType_AppIntermediateKey: retval = "Application Intermediate Key"; break; case kType_AppEpochKey: retval = "Application Epoch Key"; break; case kType_AppGroupMasterKey: retval = "Application Group Master Key"; break; default: retval = "Unknown Key Type"; } return retval; } } // namespace chip