Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2021-2022 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #pragma once 19 : 20 : #include <array> 21 : 22 : #include <lib/core/CHIPConfig.h> 23 : #include <lib/core/CHIPEncoding.h> 24 : #include <lib/core/NodeId.h> 25 : #include <lib/support/CodeUtils.h> 26 : 27 : namespace chip { 28 : 29 : typedef uint32_t CASEAuthTag; 30 : 31 : static constexpr CASEAuthTag kUndefinedCAT = 0; 32 : static constexpr NodeId kTagIdentifierMask = 0x0000'0000'FFFF'0000ULL; 33 : static constexpr uint32_t kTagIdentifierShift = 16; 34 : static constexpr NodeId kTagVersionMask = 0x0000'0000'0000'FFFFULL; 35 : 36 : // Maximum number of CASE Authenticated Tags (CAT) in the CHIP certificate subject. 37 : static constexpr size_t kMaxSubjectCATAttributeCount = CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES - 2; 38 : 39 : constexpr NodeId NodeIdFromCASEAuthTag(CASEAuthTag aCAT) 40 : { 41 : return kMinCASEAuthTag | aCAT; 42 : } 43 : 44 360 : constexpr CASEAuthTag CASEAuthTagFromNodeId(NodeId aNodeId) 45 : { 46 360 : return aNodeId & kMaskCASEAuthTag; 47 : } 48 : 49 196 : constexpr bool IsValidCASEAuthTag(CASEAuthTag aCAT) 50 : { 51 196 : return (aCAT & kTagVersionMask) > 0; 52 : } 53 : 54 114 : constexpr uint16_t GetCASEAuthTagIdentifier(CASEAuthTag aCAT) 55 : { 56 114 : return static_cast<uint16_t>((aCAT & kTagIdentifierMask) >> kTagIdentifierShift); 57 : } 58 : 59 348 : constexpr uint16_t GetCASEAuthTagVersion(CASEAuthTag aCAT) 60 : { 61 348 : return static_cast<uint16_t>(aCAT & kTagVersionMask); 62 : } 63 : 64 : struct CATValues 65 : { 66 : std::array<CASEAuthTag, kMaxSubjectCATAttributeCount> values = { kUndefinedCAT }; 67 : 68 : /* @brief Returns maximum number of CAT values that the array can contain. 69 : */ 70 775 : static constexpr size_t size() { return std::tuple_size<decltype(values)>::value; } 71 : 72 : /** 73 : * @return the number of CATs present in the set (values not equal to kUndefinedCAT) 74 : */ 75 106 : size_t GetNumTagsPresent() const 76 : { 77 106 : size_t count = 0; 78 424 : for (auto cat : values) 79 : { 80 318 : count += (cat != kUndefinedCAT) ? 1 : 0; 81 : } 82 106 : return count; 83 : } 84 : 85 : /** 86 : * @return true if `tag` is in the set exactly, false otherwise. 87 : */ 88 0 : bool Contains(CASEAuthTag tag) const 89 : { 90 0 : for (auto candidate : values) 91 : { 92 0 : if ((candidate != kUndefinedCAT) && (candidate == tag)) 93 : { 94 0 : return true; 95 : } 96 : } 97 : 98 0 : return false; 99 : } 100 : 101 142 : bool AreValid() const 102 : { 103 565 : for (size_t idx = 0; idx < size(); ++idx) 104 : { 105 424 : const auto & candidate = values[idx]; 106 424 : if (candidate == kUndefinedCAT) 107 : { 108 406 : continue; 109 : } 110 : 111 : // Every entry that is not empty must have version > 0 112 18 : if (!IsValidCASEAuthTag(candidate)) 113 : { 114 0 : return false; 115 : } 116 : // Identifiers cannot collide in set (there cannot be more than 1 version of an identifier) 117 70 : for (size_t other_idx = 0; other_idx < size(); ++other_idx) 118 : { 119 53 : if (idx == other_idx) 120 : { 121 18 : continue; 122 : } 123 35 : if (values[other_idx] == kUndefinedCAT) 124 : { 125 14 : continue; 126 : } 127 : 128 21 : uint16_t other_identifier = GetCASEAuthTagIdentifier(values[other_idx]); 129 21 : uint16_t candidate_identifier = GetCASEAuthTagIdentifier(candidate); 130 21 : if (other_identifier == candidate_identifier) 131 : { 132 1 : return false; 133 : } 134 : } 135 : } 136 : 137 141 : return true; 138 : } 139 : 140 : /** 141 : * @brief Returns true if this set contains any version of the `identifier` 142 : * 143 : * @param identifier - CAT identifier to find 144 : * @return true if the identifier is in the set, false otherwise 145 : */ 146 : bool ContainsIdentifier(uint16_t identifier) const 147 : { 148 : for (auto candidate : values) 149 : { 150 : uint16_t candidate_identifier = GetCASEAuthTagIdentifier(candidate); 151 : if ((candidate != kUndefinedCAT) && (identifier == candidate_identifier)) 152 : { 153 : return true; 154 : } 155 : } 156 : 157 : return false; 158 : } 159 : 160 : /* @brief Returns true if subject input checks against one of the CATs in the values array. 161 : */ 162 45 : bool CheckSubjectAgainstCATs(NodeId subject) const 163 : { 164 45 : VerifyOrReturnError(IsCASEAuthTag(subject), false); 165 45 : CASEAuthTag catFromSubject = CASEAuthTagFromNodeId(subject); 166 : 167 161 : for (auto catFromNoc : values) 168 : { 169 36 : if ((catFromNoc != kUndefinedCAT) && 170 47 : (GetCASEAuthTagIdentifier(catFromNoc) == GetCASEAuthTagIdentifier(catFromSubject)) && 171 171 : (GetCASEAuthTagVersion(catFromSubject) > 0) && 172 11 : (GetCASEAuthTagVersion(catFromNoc) >= GetCASEAuthTagVersion(catFromSubject))) 173 : { 174 8 : return true; 175 : } 176 : } 177 37 : return false; 178 : } 179 : 180 53 : bool operator==(const CATValues & other) const 181 : { 182 : // Two sets of CATs confer equal permissions if the sets are exactly equal 183 : // and the sets are valid. 184 : // Ignoring kUndefinedCAT values, evaluate this. 185 53 : if (this->GetNumTagsPresent() != other.GetNumTagsPresent()) 186 : { 187 0 : return false; 188 : } 189 53 : if (!this->AreValid() || !other.AreValid()) 190 : { 191 0 : return false; 192 : } 193 212 : for (auto cat : this->values) 194 : { 195 159 : if (cat == kUndefinedCAT) 196 : { 197 159 : continue; 198 : } 199 : 200 0 : if (!other.Contains(cat)) 201 : { 202 0 : return false; 203 : } 204 : } 205 53 : return true; 206 : } 207 : bool operator!=(const CATValues & other) const { return !(*this == other); } 208 : 209 : static constexpr size_t kSerializedLength = kMaxSubjectCATAttributeCount * sizeof(CASEAuthTag); 210 : typedef uint8_t Serialized[kSerializedLength]; 211 : 212 208 : CHIP_ERROR Serialize(Serialized & outSerialized) const 213 : { 214 208 : uint8_t * p = outSerialized; 215 832 : for (size_t i = 0; i < kMaxSubjectCATAttributeCount; i++) 216 : { 217 624 : Encoding::LittleEndian::Write32(p, values[i]); 218 : } 219 208 : return CHIP_NO_ERROR; 220 : } 221 : 222 318 : CHIP_ERROR Deserialize(const Serialized & inSerialized) 223 : { 224 318 : const uint8_t * p = inSerialized; 225 1272 : for (size_t i = 0; i < kMaxSubjectCATAttributeCount; i++) 226 : { 227 954 : values[i] = Encoding::LittleEndian::Read32(p); 228 : } 229 318 : return CHIP_NO_ERROR; 230 : } 231 : }; 232 : 233 : static constexpr CATValues kUndefinedCATs = { { kUndefinedCAT } }; 234 : 235 : } // namespace chip