LCOV - code coverage report
Current view: top level - lib/core - CASEAuthTag.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 57 67 85.1 %
Date: 2024-02-15 08:20:41 Functions: 11 12 91.7 %

          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

Generated by: LCOV version 1.14