| /* |
| * |
| * 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 <lib/core/CHIPKeyIds.h> |
| |
| #include <lib/support/CodeUtils.h> |
| |
| 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<uint32_t>(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 |