Matter SDK Coverage Report
Current view: top level - crypto - CHIPCryptoPAL.cpp (source / functions) Coverage Total Hit
Test: SHA:4e38905c6688effc074abecb34194a823ffbe5e5 Lines: 99.3 % 544 540
Test Date: 2025-05-10 07:09:20 Functions: 100.0 % 41 41

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-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              : /**
      19              :  *    @file
      20              :  *      Platform agnostic implementation of CHIP crypto algorithms
      21              :  */
      22              : 
      23              : #include "CHIPCryptoPAL.h"
      24              : 
      25              : #include "SessionKeystore.h"
      26              : 
      27              : #include <lib/asn1/ASN1.h>
      28              : #include <lib/asn1/ASN1Macros.h>
      29              : #include <lib/core/CHIPEncoding.h>
      30              : #include <lib/support/BufferReader.h>
      31              : #include <lib/support/BufferWriter.h>
      32              : #include <lib/support/BytesToHex.h>
      33              : #include <lib/support/CodeUtils.h>
      34              : #include <lib/support/Span.h>
      35              : #include <lib/support/TypeTraits.h>
      36              : #include <stdint.h>
      37              : #include <string.h>
      38              : 
      39              : using chip::ByteSpan;
      40              : using chip::MutableByteSpan;
      41              : using chip::Encoding::BufferWriter;
      42              : using chip::Encoding::LittleEndian::Reader;
      43              : 
      44              : using namespace chip::ASN1;
      45              : 
      46              : namespace chip {
      47              : namespace Crypto {
      48              : namespace {
      49              : 
      50              : constexpr uint8_t kIntegerTag         = 0x02u;
      51              : constexpr uint8_t kSeqTag             = 0x30u;
      52              : constexpr size_t kMinSequenceOverhead = 1 /* tag */ + 1 /* length */ + 1 /* actual data or second length byte*/;
      53              : 
      54              : /**
      55              :  * @brief Utility to convert DER-encoded INTEGER into a raw integer buffer in big-endian order
      56              :  *        with leading zeroes if the output buffer is larger than needed.
      57              :  * @param[in] reader Reader instance from which the input will be read
      58              :  * @param[out] raw_integer_out Buffer to receive the DER-encoded integer
      59              :  * @return CHIP_ERROR_INVALID_ARGUMENT or CHIP_ERROR_BUFFER_TOO_SMALL on error, CHIP_NO_ERROR otherwise
      60              :  */
      61          368 : CHIP_ERROR ReadDerUnsignedIntegerIntoRaw(Reader & reader, MutableByteSpan raw_integer_out)
      62              : {
      63          368 :     uint8_t cur_byte = 0;
      64              : 
      65          368 :     ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
      66              : 
      67              :     // We expect first tag to be INTEGER
      68          368 :     VerifyOrReturnError(cur_byte == kIntegerTag, CHIP_ERROR_INVALID_ARGUMENT);
      69              : 
      70              :     // Read the length
      71          368 :     size_t integer_len = 0;
      72          368 :     ReturnErrorOnFailure(chip::Crypto::ReadDerLength(reader, integer_len));
      73              : 
      74              :     // Clear the destination buffer, so we can blit the unsigned value into place
      75          368 :     memset(raw_integer_out.data(), 0, raw_integer_out.size());
      76              : 
      77              :     // Check for pseudo-zero to mark unsigned value
      78              :     // This means we have too large an integer (should be at most 1 byte too large), it's invalid
      79          368 :     VerifyOrReturnError(integer_len <= (raw_integer_out.size() + 1), CHIP_ERROR_INVALID_ARGUMENT);
      80              : 
      81          368 :     if (integer_len == (raw_integer_out.size() + 1u))
      82              :     {
      83              :         // Means we had a 0x00 byte stuffed due to MSB being high in original integer
      84          206 :         ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
      85              : 
      86              :         // The extra byte must be a leading zero
      87          206 :         VerifyOrReturnError(cur_byte == 0, CHIP_ERROR_INVALID_ARGUMENT);
      88          206 :         --integer_len;
      89              :     }
      90              : 
      91              :     // We now have the rest of the tag that is a "minimal length" unsigned integer.
      92              :     // Blit it at the correct offset, since the order we use is MSB first for
      93              :     // both ASN.1 and EC curve raw points.
      94          368 :     size_t offset = raw_integer_out.size() - integer_len;
      95          368 :     return reader.ReadBytes(raw_integer_out.data() + offset, integer_len).StatusCode();
      96              : }
      97              : 
      98          263 : CHIP_ERROR ConvertIntegerRawToDerInternal(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer,
      99              :                                           bool include_tag_and_length)
     100              : {
     101          263 :     if (raw_integer.empty() || out_der_integer.empty())
     102              :     {
     103            2 :         return CHIP_ERROR_INVALID_ARGUMENT;
     104              :     }
     105              : 
     106          261 :     Reader reader(raw_integer);
     107          261 :     BufferWriter writer(out_der_integer);
     108              : 
     109          261 :     bool needs_leading_zero_byte = false;
     110              : 
     111          261 :     uint8_t cur_byte = 0;
     112          445 :     while ((reader.Remaining() > 0) && (reader.Read8(&cur_byte).StatusCode() == CHIP_NO_ERROR) && (cur_byte == 0))
     113              :     {
     114              :         // Omit all leading zeros
     115              :     }
     116              : 
     117          261 :     if ((cur_byte & 0x80u) != 0)
     118              :     {
     119              :         // If overall MSB (from leftmost byte) is set, we will need to push out a zero to avoid it being
     120              :         // considered a negative number.
     121          127 :         needs_leading_zero_byte = true;
     122              :     }
     123              : 
     124              :     // The + 1 is to account for the last consumed byte of the loop to skip leading zeros
     125          261 :     size_t length = reader.Remaining() + 1 + (needs_leading_zero_byte ? 1 : 0);
     126              : 
     127          261 :     if (length > 127)
     128              :     {
     129              :         // We do not support length over more than 1 bytes.
     130            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     131              :     }
     132              : 
     133          261 :     if (include_tag_and_length)
     134              :     {
     135              :         // Put INTEGER tag
     136           24 :         writer.Put(kIntegerTag);
     137              : 
     138              :         // Put length over 1 byte (i.e. MSB clear)
     139           24 :         writer.Put(static_cast<uint8_t>(length));
     140              :     }
     141              : 
     142              :     // If leading zero or no more bytes remaining, must ensure we start with at least a zero byte
     143          261 :     if (needs_leading_zero_byte)
     144              :     {
     145          127 :         writer.Put(static_cast<uint8_t>(0u));
     146              :     }
     147              : 
     148              :     // Put first consumed byte from last read iteration of leading zero suppression
     149          261 :     writer.Put(cur_byte);
     150              : 
     151              :     // Fill the rest from the input in order
     152         7704 :     while (reader.Read8(&cur_byte).StatusCode() == CHIP_NO_ERROR)
     153              :     {
     154              :         // Emit all other bytes as-is
     155         7443 :         writer.Put(cur_byte);
     156              :     }
     157              : 
     158          261 :     size_t actually_written = 0;
     159          261 :     if (!writer.Fit(actually_written))
     160              :     {
     161            7 :         return CHIP_ERROR_BUFFER_TOO_SMALL;
     162              :     }
     163              : 
     164          254 :     out_der_integer = out_der_integer.SubSpan(0, actually_written);
     165              : 
     166          254 :     return CHIP_NO_ERROR;
     167              : }
     168              : 
     169              : /**
     170              :  * @brief Find a 4 uppercase hex digit hex value after a prefix string. Used to implement
     171              :  *        fallback CN VID/PID encoding for PAA/PAI/DAC.
     172              :  *
     173              :  * @param[in] buffer - buffer in which to find the substring.
     174              :  * @param[in] prefix - prefix to match, which must be followed by 4 uppercase hex characters
     175              :  * @param[out] out_hex_value - on CHIP_NO_ERROR return, this will be the 16-bit hex value decoded.
     176              :  * @return CHIP_NO_ERROR on success, CHIP_ERROR_NOT_FOUND if not detected and
     177              :  *         CHIP_ERROR_WRONG_CERT_DN if we saw the prefix but no valid hex string.
     178              :  */
     179          679 : CHIP_ERROR Find16BitUpperCaseHexAfterPrefix(const ByteSpan & buffer, const char * prefix, uint16_t & out_hex_value)
     180              : {
     181          679 :     chip::CharSpan prefix_span = chip::CharSpan::fromCharString(prefix);
     182              : 
     183          679 :     bool found_prefix_at_least_once = false;
     184              : 
     185              :     // Scan string from left to right, to find the desired full matching substring.
     186              :     //
     187              :     // IMPORTANT NOTE: We are trying to find the equivalent of prefix + [0-9A-F]{4}.
     188              :     // The appearance of the full prefix, but not followed by the hex value, must
     189              :     // be detected, as it is illegal if there isn't a valid prefix within the string.
     190              :     // This is why we first check for the prefix and then maybe check for the hex
     191              :     // value, rather than doing a single check of making sure there is enough space
     192              :     // for both.
     193         9852 :     for (size_t start_idx = 0; start_idx < buffer.size(); start_idx++)
     194              :     {
     195         9852 :         const uint8_t * cursor = buffer.data() + start_idx;
     196         9852 :         size_t remaining       = buffer.size() - start_idx;
     197              : 
     198         9852 :         if (remaining < prefix_span.size())
     199              :         {
     200              :             // We can't possibly match prefix if not enough bytes left.
     201          607 :             break;
     202              :         }
     203              : 
     204              :         // Try to match the prefix at current position.
     205         9248 :         if (memcmp(cursor, prefix_span.data(), prefix_span.size()) != 0)
     206              :         {
     207              :             // Did not find prefix, move to next position.
     208         9154 :             continue;
     209              :         }
     210              : 
     211              :         // Otherwise, found prefix, skip to possible hex value.
     212           94 :         found_prefix_at_least_once = true;
     213           94 :         cursor += prefix_span.size();
     214           94 :         remaining -= prefix_span.size();
     215              : 
     216           94 :         constexpr size_t expected_hex_len = HEX_ENCODED_LENGTH(sizeof(uint16_t));
     217           94 :         if (remaining < expected_hex_len)
     218              :         {
     219              :             // We can't possibly match the hex values if not enough bytes left.
     220            3 :             break;
     221              :         }
     222              : 
     223              :         char hex_buf[expected_hex_len];
     224           91 :         memcpy(&hex_buf[0], cursor, sizeof(hex_buf));
     225              : 
     226           91 :         if (Encoding::UppercaseHexToUint16(&hex_buf[0], sizeof(hex_buf), out_hex_value) != 0)
     227              :         {
     228              :             // Found first full valid match, return success, out_hex_value already updated.
     229           72 :             return CHIP_NO_ERROR;
     230              :         }
     231              : 
     232              :         // Otherwise, did not find what we were looking for, try next position until exhausted.
     233              :     }
     234              : 
     235          607 :     return found_prefix_at_least_once ? CHIP_ERROR_WRONG_CERT_DN : CHIP_ERROR_NOT_FOUND;
     236              : }
     237              : 
     238              : } // namespace
     239              : 
     240              : using HKDF_sha_crypto = HKDF_sha;
     241              : 
     242          328 : CHIP_ERROR Spake2p::InternalHash(const uint8_t * in, size_t in_len)
     243              : {
     244          328 :     const uint64_t u64_len = in_len;
     245              : 
     246              :     uint8_t lb[8];
     247          328 :     lb[0] = static_cast<uint8_t>((u64_len >> 0) & 0xff);
     248          328 :     lb[1] = static_cast<uint8_t>((u64_len >> 8) & 0xff);
     249          328 :     lb[2] = static_cast<uint8_t>((u64_len >> 16) & 0xff);
     250          328 :     lb[3] = static_cast<uint8_t>((u64_len >> 24) & 0xff);
     251          328 :     lb[4] = static_cast<uint8_t>((u64_len >> 32) & 0xff);
     252          328 :     lb[5] = static_cast<uint8_t>((u64_len >> 40) & 0xff);
     253          328 :     lb[6] = static_cast<uint8_t>((u64_len >> 48) & 0xff);
     254          328 :     lb[7] = static_cast<uint8_t>((u64_len >> 56) & 0xff);
     255              : 
     256          328 :     ReturnErrorOnFailure(Hash(lb, sizeof(lb)));
     257          328 :     if (in != nullptr)
     258              :     {
     259          179 :         ReturnErrorOnFailure(Hash(in, in_len));
     260              :     }
     261              : 
     262          328 :     return CHIP_NO_ERROR;
     263              : }
     264              : 
     265          151 : Spake2p::Spake2p(size_t _fe_size, size_t _point_size, size_t _hash_size)
     266              : {
     267          151 :     fe_size    = _fe_size;
     268          151 :     point_size = _point_size;
     269          151 :     hash_size  = _hash_size;
     270              : 
     271          151 :     Kca = &Kcab[0];
     272          151 :     Kcb = &Kcab[hash_size / 2];
     273          151 :     Ka  = &Kae[0];
     274          151 :     Ke  = &Kae[hash_size / 2];
     275              : 
     276          151 :     M  = nullptr;
     277          151 :     N  = nullptr;
     278          151 :     G  = nullptr;
     279          151 :     X  = nullptr;
     280          151 :     Y  = nullptr;
     281          151 :     L  = nullptr;
     282          151 :     Z  = nullptr;
     283          151 :     V  = nullptr;
     284          151 :     w0 = nullptr;
     285          151 :     w1 = nullptr;
     286          151 :     xy = nullptr;
     287              : 
     288          151 :     order  = nullptr;
     289          151 :     tempbn = nullptr;
     290          151 : }
     291              : 
     292          148 : CHIP_ERROR Spake2p::Init(const uint8_t * context, size_t context_len)
     293              : {
     294          148 :     if (state != CHIP_SPAKE2P_STATE::PREINIT)
     295              :     {
     296            1 :         Clear();
     297              :     }
     298              : 
     299          148 :     ReturnErrorOnFailure(InitImpl());
     300          148 :     ReturnErrorOnFailure(PointLoad(spake2p_M_p256, sizeof(spake2p_M_p256), M));
     301          148 :     ReturnErrorOnFailure(PointLoad(spake2p_N_p256, sizeof(spake2p_N_p256), N));
     302          148 :     ReturnErrorOnFailure(InternalHash(context, context_len));
     303              : 
     304          148 :     state = CHIP_SPAKE2P_STATE::INIT;
     305          148 :     return CHIP_NO_ERROR;
     306              : }
     307              : 
     308           20 : CHIP_ERROR Spake2p::WriteMN()
     309              : {
     310           20 :     ReturnErrorOnFailure(InternalHash(spake2p_M_p256, sizeof(spake2p_M_p256)));
     311           20 :     ReturnErrorOnFailure(InternalHash(spake2p_N_p256, sizeof(spake2p_N_p256)));
     312              : 
     313           20 :     return CHIP_NO_ERROR;
     314              : }
     315              : 
     316           10 : CHIP_ERROR Spake2p::BeginVerifier(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity,
     317              :                                   size_t peer_identity_len, const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin,
     318              :                                   size_t Lin_len)
     319              : {
     320           10 :     VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL);
     321              : 
     322           10 :     ReturnErrorOnFailure(InternalHash(peer_identity, peer_identity_len));
     323           10 :     ReturnErrorOnFailure(InternalHash(my_identity, my_identity_len));
     324           10 :     ReturnErrorOnFailure(WriteMN());
     325           10 :     ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0));
     326           10 :     ReturnErrorOnFailure(PointLoad(Lin, Lin_len, L));
     327              : 
     328           10 :     state = CHIP_SPAKE2P_STATE::STARTED;
     329           10 :     role  = CHIP_SPAKE2P_ROLE::VERIFIER;
     330           10 :     return CHIP_NO_ERROR;
     331              : }
     332              : 
     333           10 : CHIP_ERROR Spake2p::BeginProver(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity,
     334              :                                 size_t peer_identity_len, const uint8_t * w0sin, size_t w0sin_len, const uint8_t * w1sin,
     335              :                                 size_t w1sin_len)
     336              : {
     337           10 :     VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL);
     338              : 
     339           10 :     ReturnErrorOnFailure(InternalHash(my_identity, my_identity_len));
     340           10 :     ReturnErrorOnFailure(InternalHash(peer_identity, peer_identity_len));
     341           10 :     ReturnErrorOnFailure(WriteMN());
     342           10 :     ReturnErrorOnFailure(FELoad(w0sin, w0sin_len, w0));
     343           10 :     ReturnErrorOnFailure(FELoad(w1sin, w1sin_len, w1));
     344              : 
     345           10 :     state = CHIP_SPAKE2P_STATE::STARTED;
     346           10 :     role  = CHIP_SPAKE2P_ROLE::PROVER;
     347           10 :     return CHIP_NO_ERROR;
     348              : }
     349              : 
     350           20 : CHIP_ERROR Spake2p::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len)
     351              : {
     352           20 :     CHIP_ERROR error = CHIP_ERROR_INTERNAL;
     353           20 :     void * MN        = nullptr; // Choose M if a prover, N if a verifier
     354           20 :     void * XY        = nullptr; // Choose X if a prover, Y if a verifier
     355              : 
     356           20 :     VerifyOrExit(state == CHIP_SPAKE2P_STATE::STARTED, error = CHIP_ERROR_INTERNAL);
     357           20 :     VerifyOrExit(*out_len >= point_size, error = CHIP_ERROR_INTERNAL);
     358              : 
     359           20 :     ReturnErrorOnFailure(FEGenerate(xy));
     360              : 
     361           20 :     if (role == CHIP_SPAKE2P_ROLE::PROVER)
     362              :     {
     363           10 :         MN = M;
     364           10 :         XY = X;
     365              :     }
     366           10 :     else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
     367              :     {
     368           10 :         MN = N;
     369           10 :         XY = Y;
     370              :     }
     371           20 :     VerifyOrExit(MN != nullptr, error = CHIP_ERROR_INTERNAL);
     372           20 :     VerifyOrExit(XY != nullptr, error = CHIP_ERROR_INTERNAL);
     373              : 
     374           20 :     SuccessOrExit(error = PointAddMul(XY, G, xy, MN, w0));
     375           20 :     SuccessOrExit(error = PointWrite(XY, out, *out_len));
     376              : 
     377           20 :     state = CHIP_SPAKE2P_STATE::R1;
     378           20 :     error = CHIP_NO_ERROR;
     379           20 : exit:
     380           20 :     *out_len = point_size;
     381           20 :     return error;
     382              : }
     383              : 
     384           20 : CHIP_ERROR Spake2p::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len)
     385              : {
     386           20 :     CHIP_ERROR error = CHIP_ERROR_INTERNAL;
     387           20 :     MutableByteSpan out_span{ out, *out_len };
     388              :     uint8_t point_buffer[kMAX_Point_Length];
     389           20 :     void * MN        = nullptr; // Choose N if a prover, M if a verifier
     390           20 :     void * XY        = nullptr; // Choose Y if a prover, X if a verifier
     391           20 :     uint8_t * Kcaorb = nullptr; // Choose Kca if a prover, Kcb if a verifier
     392              : 
     393           20 :     VerifyOrExit(*out_len >= hash_size, error = CHIP_ERROR_INTERNAL);
     394           20 :     VerifyOrExit(state == CHIP_SPAKE2P_STATE::R1, error = CHIP_ERROR_INTERNAL);
     395           20 :     VerifyOrExit(in_len == point_size, error = CHIP_ERROR_INTERNAL);
     396              : 
     397           20 :     if (role == CHIP_SPAKE2P_ROLE::PROVER)
     398              :     {
     399           10 :         SuccessOrExit(error = PointWrite(X, point_buffer, point_size));
     400           10 :         SuccessOrExit(error = InternalHash(point_buffer, point_size));
     401           10 :         SuccessOrExit(error = InternalHash(in, in_len));
     402              : 
     403           10 :         MN     = N;
     404           10 :         XY     = Y;
     405           10 :         Kcaorb = Kca;
     406              :     }
     407           10 :     else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
     408              :     {
     409           10 :         SuccessOrExit(error = InternalHash(in, in_len));
     410           10 :         SuccessOrExit(error = PointWrite(Y, point_buffer, point_size));
     411           10 :         SuccessOrExit(error = InternalHash(point_buffer, point_size));
     412              : 
     413           10 :         MN     = M;
     414           10 :         XY     = X;
     415           10 :         Kcaorb = Kcb;
     416              :     }
     417           20 :     VerifyOrExit(MN != nullptr, error = CHIP_ERROR_INTERNAL);
     418           20 :     VerifyOrExit(XY != nullptr, error = CHIP_ERROR_INTERNAL);
     419              : 
     420           20 :     SuccessOrExit(error = PointLoad(in, in_len, XY));
     421           20 :     SuccessOrExit(error = PointIsValid(XY));
     422           20 :     SuccessOrExit(error = FEMul(tempbn, xy, w0));
     423           20 :     SuccessOrExit(error = PointInvert(MN));
     424           20 :     SuccessOrExit(error = PointAddMul(Z, XY, xy, MN, tempbn));
     425           20 :     SuccessOrExit(error = PointCofactorMul(Z));
     426              : 
     427           20 :     if (role == CHIP_SPAKE2P_ROLE::PROVER)
     428              :     {
     429           10 :         SuccessOrExit(error = FEMul(tempbn, w1, w0));
     430           10 :         SuccessOrExit(error = PointAddMul(V, XY, w1, MN, tempbn));
     431              :     }
     432           10 :     else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
     433              :     {
     434           10 :         SuccessOrExit(error = PointMul(V, L, xy));
     435              :     }
     436              : 
     437           20 :     SuccessOrExit(error = PointCofactorMul(V));
     438           20 :     SuccessOrExit(error = PointWrite(Z, point_buffer, point_size));
     439           20 :     SuccessOrExit(error = InternalHash(point_buffer, point_size));
     440              : 
     441           20 :     SuccessOrExit(error = PointWrite(V, point_buffer, point_size));
     442           20 :     SuccessOrExit(error = InternalHash(point_buffer, point_size));
     443              : 
     444           20 :     SuccessOrExit(error = FEWrite(w0, point_buffer, fe_size));
     445           20 :     SuccessOrExit(error = InternalHash(point_buffer, fe_size));
     446              : 
     447           20 :     SuccessOrExit(error = GenerateKeys());
     448              : 
     449           20 :     SuccessOrExit(error = Mac(Kcaorb, hash_size / 2, in, in_len, out_span));
     450           20 :     VerifyOrExit(out_span.size() == hash_size, error = CHIP_ERROR_INTERNAL);
     451              : 
     452           20 :     state = CHIP_SPAKE2P_STATE::R2;
     453           20 :     error = CHIP_NO_ERROR;
     454           20 : exit:
     455           20 :     *out_len = hash_size;
     456           20 :     return error;
     457              : }
     458              : 
     459           20 : CHIP_ERROR Spake2p::GenerateKeys()
     460              : {
     461              :     static const uint8_t info_keyconfirm[16] = { 'C', 'o', 'n', 'f', 'i', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'K', 'e', 'y', 's' };
     462              : 
     463           20 :     MutableByteSpan Kae_span{ &Kae[0], sizeof(Kae) };
     464              : 
     465           20 :     ReturnErrorOnFailure(HashFinalize(Kae_span));
     466           20 :     ReturnErrorOnFailure(KDF(Ka, hash_size / 2, nullptr, 0, info_keyconfirm, sizeof(info_keyconfirm), Kcab, hash_size));
     467              : 
     468           20 :     return CHIP_NO_ERROR;
     469              : }
     470              : 
     471           19 : CHIP_ERROR Spake2p::KeyConfirm(const uint8_t * in, size_t in_len)
     472              : {
     473              :     uint8_t point_buffer[kP256_Point_Length];
     474           19 :     void * XY        = nullptr; // Choose X if a prover, Y if a verifier
     475           19 :     uint8_t * Kcaorb = nullptr; // Choose Kcb if a prover, Kca if a verifier
     476              : 
     477           19 :     VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::R2, CHIP_ERROR_INTERNAL);
     478              : 
     479           19 :     if (role == CHIP_SPAKE2P_ROLE::PROVER)
     480              :     {
     481           10 :         XY     = X;
     482           10 :         Kcaorb = Kcb;
     483              :     }
     484            9 :     else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
     485              :     {
     486            9 :         XY     = Y;
     487            9 :         Kcaorb = Kca;
     488              :     }
     489           19 :     VerifyOrReturnError(XY != nullptr, CHIP_ERROR_INTERNAL);
     490           19 :     VerifyOrReturnError(Kcaorb != nullptr, CHIP_ERROR_INTERNAL);
     491              : 
     492           19 :     ReturnErrorOnFailure(PointWrite(XY, point_buffer, point_size));
     493              : 
     494           19 :     CHIP_ERROR err = MacVerify(Kcaorb, hash_size / 2, in, in_len, point_buffer, point_size);
     495           19 :     if (err == CHIP_ERROR_INTERNAL)
     496              :     {
     497            1 :         ChipLogError(SecureChannel, "Failed to verify peer's MAC. This can happen when setup code is incorrect.");
     498              :     }
     499           19 :     ReturnErrorOnFailure(err);
     500              : 
     501           18 :     state = CHIP_SPAKE2P_STATE::KC;
     502           18 :     return CHIP_NO_ERROR;
     503              : }
     504              : 
     505           18 : CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
     506              : {
     507           18 :     VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::KC, CHIP_ERROR_INTERNAL);
     508              : 
     509           18 :     return keystore.CreateKey(ByteSpan(Ke, hash_size / 2), key);
     510              : }
     511              : 
     512          148 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::InitImpl()
     513              : {
     514          148 :     ReturnErrorOnFailure(sha256_hash_ctx.Begin());
     515          148 :     ReturnErrorOnFailure(InitInternal());
     516          148 :     return CHIP_NO_ERROR;
     517              : }
     518              : 
     519          507 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Hash(const uint8_t * in, size_t in_len)
     520              : {
     521          507 :     ReturnErrorOnFailure(sha256_hash_ctx.AddData(ByteSpan{ in, in_len }));
     522          507 :     return CHIP_NO_ERROR;
     523              : }
     524              : 
     525           20 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::HashFinalize(MutableByteSpan & out_span)
     526              : {
     527           20 :     ReturnErrorOnFailure(sha256_hash_ctx.Finish(out_span));
     528           20 :     return CHIP_NO_ERROR;
     529              : }
     530              : 
     531           20 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::KDF(const uint8_t * ikm, const size_t ikm_len, const uint8_t * salt,
     532              :                                               const size_t salt_len, const uint8_t * info, const size_t info_len, uint8_t * out,
     533              :                                               size_t out_len)
     534              : {
     535           20 :     HKDF_sha_crypto mHKDF;
     536              : 
     537           20 :     ReturnErrorOnFailure(mHKDF.HKDF_SHA256(ikm, ikm_len, salt, salt_len, info, info_len, out, out_len));
     538              : 
     539           20 :     return CHIP_NO_ERROR;
     540           20 : }
     541              : 
     542            3 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeW0(uint8_t * w0out, size_t * w0_len, const uint8_t * w0sin, size_t w0sin_len)
     543              : {
     544            3 :     ReturnErrorOnFailure(FELoad(w0sin, w0sin_len, w0));
     545            3 :     ReturnErrorOnFailure(FEWrite(w0, w0out, *w0_len));
     546              : 
     547            3 :     return CHIP_NO_ERROR;
     548              : }
     549              : 
     550            2 : CHIP_ERROR Spake2pVerifier::Serialize(MutableByteSpan & outSerialized) const
     551              : {
     552            2 :     VerifyOrReturnError(outSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
     553              : 
     554            2 :     memcpy(&outSerialized.data()[0], mW0, sizeof(mW0));
     555            2 :     memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL));
     556              : 
     557            2 :     outSerialized.reduce_size(kSpake2p_VerifierSerialized_Length);
     558              : 
     559            2 :     return CHIP_NO_ERROR;
     560              : }
     561              : 
     562            9 : CHIP_ERROR Spake2pVerifier::Deserialize(const ByteSpan & inSerialized)
     563              : {
     564            9 :     VerifyOrReturnError(inSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
     565              : 
     566            8 :     memcpy(mW0, &inSerialized.data()[0], sizeof(mW0));
     567            8 :     memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL));
     568              : 
     569            8 :     return CHIP_NO_ERROR;
     570              : }
     571              : 
     572            3 : CHIP_ERROR Spake2pVerifier::Generate(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin)
     573              : {
     574            3 :     uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
     575            3 :     ReturnErrorOnFailure(ComputeWS(pbkdf2IterCount, salt, setupPin, serializedWS, sizeof(serializedWS)));
     576              : 
     577            3 :     CHIP_ERROR err = CHIP_NO_ERROR;
     578              :     size_t len;
     579              : 
     580              :     // Create local Spake2+ object for w0 and L computations.
     581            3 :     Spake2p_P256_SHA256_HKDF_HMAC spake2p;
     582            3 :     uint8_t context[kSHA256_Hash_Length] = { 0 };
     583            3 :     SuccessOrExit(err = spake2p.Init(context, sizeof(context)));
     584              : 
     585              :     // Compute w0
     586            3 :     len = sizeof(mW0);
     587            3 :     SuccessOrExit(err = spake2p.ComputeW0(mW0, &len, &serializedWS[0], kSpake2p_WS_Length));
     588            3 :     VerifyOrExit(len == sizeof(mW0), err = CHIP_ERROR_INTERNAL);
     589              : 
     590              :     // Compute L
     591            3 :     len = sizeof(mL);
     592            3 :     SuccessOrExit(err = spake2p.ComputeL(mL, &len, &serializedWS[kSpake2p_WS_Length], kSpake2p_WS_Length));
     593            3 :     VerifyOrExit(len == sizeof(mL), err = CHIP_ERROR_INTERNAL);
     594              : 
     595            3 : exit:
     596            3 :     spake2p.Clear();
     597            3 :     return err;
     598            3 : }
     599              : 
     600            9 : CHIP_ERROR Spake2pVerifier::ComputeWS(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin, uint8_t * ws,
     601              :                                       uint32_t ws_len)
     602              : {
     603            9 :     PBKDF2_sha256 pbkdf2;
     604              :     uint8_t littleEndianSetupPINCode[sizeof(uint32_t)];
     605            9 :     Encoding::LittleEndian::Put32(littleEndianSetupPINCode, setupPin);
     606              : 
     607            9 :     VerifyOrReturnError(salt.size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
     608              :                         CHIP_ERROR_INVALID_ARGUMENT);
     609            9 :     VerifyOrReturnError(pbkdf2IterCount >= kSpake2p_Min_PBKDF_Iterations && pbkdf2IterCount <= kSpake2p_Max_PBKDF_Iterations,
     610              :                         CHIP_ERROR_INVALID_ARGUMENT);
     611              : 
     612            9 :     return pbkdf2.pbkdf2_sha256(littleEndianSetupPINCode, sizeof(littleEndianSetupPINCode), salt.data(), salt.size(),
     613            9 :                                 pbkdf2IterCount, ws_len, ws);
     614            9 : }
     615              : 
     616          625 : CHIP_ERROR ReadDerLength(Reader & reader, size_t & length)
     617              : {
     618          625 :     length = 0;
     619              : 
     620          625 :     uint8_t cur_byte = 0;
     621          625 :     ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
     622              : 
     623          624 :     if ((cur_byte & (1u << 7)) == 0)
     624              :     {
     625              :         // 7 bit length, the rest of the byte is the length.
     626          553 :         length = cur_byte & 0x7Fu;
     627          553 :         return CHIP_NO_ERROR;
     628              :     }
     629              : 
     630           71 :     CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT;
     631              : 
     632              :     // Did not early return: > 7 bit length, the number of bytes of the length is provided next.
     633           71 :     uint8_t length_bytes = cur_byte & 0x7Fu;
     634           71 :     VerifyOrReturnError((length_bytes >= 1) && (length_bytes <= sizeof(size_t)), CHIP_ERROR_INVALID_ARGUMENT);
     635           70 :     VerifyOrReturnError(reader.HasAtLeast(length_bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
     636              : 
     637          148 :     for (uint8_t i = 0; i < length_bytes; i++)
     638              :     {
     639           83 :         uint8_t cur_length_byte = 0;
     640           83 :         err                     = reader.Read8(&cur_length_byte).StatusCode();
     641           83 :         if (err != CHIP_NO_ERROR)
     642            0 :             break;
     643              : 
     644              :         // Cannot have zero padding on multi-byte lengths in DER, so first
     645              :         // byte must always be > 0.
     646           83 :         if ((i == 0) && (cur_length_byte == 0))
     647              :         {
     648            2 :             return CHIP_ERROR_INVALID_ARGUMENT;
     649              :         }
     650              : 
     651           81 :         length <<= 8;
     652           81 :         length |= cur_length_byte;
     653              :     }
     654              : 
     655              :     // Single-byte long length cannot be < 128: DER always encodes on smallest size
     656              :     // possible, so length zero should have been a single byte short length.
     657           65 :     if ((length_bytes == 1) && (length < 128))
     658              :     {
     659            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     660              :     }
     661              : 
     662           64 :     return CHIP_NO_ERROR;
     663              : }
     664              : 
     665          239 : CHIP_ERROR ConvertIntegerRawToDerWithoutTag(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer)
     666              : {
     667          239 :     return ConvertIntegerRawToDerInternal(raw_integer, out_der_integer, /* include_tag_and_length = */ false);
     668              : }
     669              : 
     670           24 : CHIP_ERROR ConvertIntegerRawToDer(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer)
     671              : {
     672           24 :     return ConvertIntegerRawToDerInternal(raw_integer, out_der_integer, /* include_tag_and_length = */ true);
     673              : }
     674              : 
     675            5 : CHIP_ERROR EcdsaRawSignatureToAsn1(size_t fe_length_bytes, const ByteSpan & raw_sig, MutableByteSpan & out_asn1_sig)
     676              : {
     677            5 :     VerifyOrReturnError(fe_length_bytes > 0, CHIP_ERROR_INVALID_ARGUMENT);
     678            5 :     VerifyOrReturnError(raw_sig.size() == (2u * fe_length_bytes), CHIP_ERROR_INVALID_ARGUMENT);
     679            5 :     VerifyOrReturnError(out_asn1_sig.size() >= (raw_sig.size() + kMax_ECDSA_X9Dot62_Asn1_Overhead), CHIP_ERROR_BUFFER_TOO_SMALL);
     680              : 
     681              :     // Write both R an S integers past the overhead, we will shift them back later if we only needed 2 size bytes.
     682            5 :     uint8_t * cursor = out_asn1_sig.data() + kMinSequenceOverhead;
     683            5 :     size_t remaining = out_asn1_sig.size() - kMinSequenceOverhead;
     684              : 
     685            5 :     size_t integers_length = 0;
     686              : 
     687              :     // Write R (first `fe_length_bytes` block of raw signature)
     688              :     {
     689            5 :         MutableByteSpan out_der_integer(cursor, remaining);
     690            5 :         ReturnErrorOnFailure(ConvertIntegerRawToDer(raw_sig.SubSpan(0, fe_length_bytes), out_der_integer));
     691            5 :         VerifyOrReturnError(out_der_integer.size() <= remaining, CHIP_ERROR_INTERNAL);
     692              : 
     693            5 :         integers_length += out_der_integer.size();
     694            5 :         remaining -= out_der_integer.size();
     695            5 :         cursor += out_der_integer.size();
     696              :     }
     697              : 
     698              :     // Write S (second `fe_length_bytes` block of raw signature)
     699              :     {
     700            5 :         MutableByteSpan out_der_integer(cursor, remaining);
     701            5 :         ReturnErrorOnFailure(ConvertIntegerRawToDer(raw_sig.SubSpan(fe_length_bytes, fe_length_bytes), out_der_integer));
     702            5 :         VerifyOrReturnError(out_der_integer.size() <= remaining, CHIP_ERROR_INTERNAL);
     703            5 :         integers_length += out_der_integer.size();
     704              :     }
     705              : 
     706              :     // We only support outputs that would use 1 or 2 bytes of DER length after the SEQUENCE tag
     707            5 :     VerifyOrReturnError(integers_length <= UINT8_MAX, CHIP_ERROR_INVALID_ARGUMENT);
     708              : 
     709              :     // We now know the length of both variable sized integers in the sequence, so we
     710              :     // can write the tag and length.
     711            5 :     BufferWriter writer(out_asn1_sig);
     712              : 
     713              :     // Put SEQUENCE tag
     714            5 :     writer.Put(kSeqTag);
     715              : 
     716              :     // Put the length over 1 or two bytes depending on case
     717            5 :     constexpr uint8_t kExtendedLengthMarker = 0x80u;
     718            5 :     if (integers_length > 127u)
     719              :     {
     720            1 :         writer.Put(static_cast<uint8_t>(kExtendedLengthMarker | 1)); // Length is extended length, over 1 subsequent byte
     721            1 :         writer.Put(static_cast<uint8_t>(integers_length));
     722              :     }
     723              :     else
     724              :     {
     725              :         // Length is directly in the first byte with MSB clear if <= 127.
     726            4 :         writer.Put(static_cast<uint8_t>(integers_length));
     727              :     }
     728              : 
     729              :     // Put the contents of the integers previously serialized in the buffer.
     730              :     // The writer.Put is memmove-safe, so the shifting will happen from the read
     731              :     // of the same buffer where the write is taking place.
     732            5 :     writer.Put(out_asn1_sig.data() + kMinSequenceOverhead, integers_length);
     733              : 
     734            5 :     size_t actually_written = 0;
     735            5 :     VerifyOrReturnError(writer.Fit(actually_written), CHIP_ERROR_BUFFER_TOO_SMALL);
     736              : 
     737            5 :     out_asn1_sig = out_asn1_sig.SubSpan(0, actually_written);
     738            5 :     return CHIP_NO_ERROR;
     739              : }
     740              : 
     741          184 : CHIP_ERROR EcdsaAsn1SignatureToRaw(size_t fe_length_bytes, const ByteSpan & asn1_sig, MutableByteSpan & out_raw_sig)
     742              : {
     743          184 :     VerifyOrReturnError(fe_length_bytes > 0, CHIP_ERROR_INVALID_ARGUMENT);
     744          184 :     VerifyOrReturnError(asn1_sig.size() > kMinSequenceOverhead, CHIP_ERROR_BUFFER_TOO_SMALL);
     745              : 
     746              :     // Output raw signature is <r,s> both of which are of fe_length_bytes (see SEC1).
     747          184 :     VerifyOrReturnError(out_raw_sig.size() >= (2u * fe_length_bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
     748              : 
     749          184 :     Reader reader(asn1_sig);
     750              : 
     751              :     // Make sure we have a starting Sequence
     752          184 :     uint8_t tag = 0;
     753          184 :     ReturnErrorOnFailure(reader.Read8(&tag).StatusCode());
     754          184 :     VerifyOrReturnError(tag == kSeqTag, CHIP_ERROR_INVALID_ARGUMENT);
     755              : 
     756              :     // Read length of sequence
     757          184 :     size_t tag_len = 0;
     758          184 :     ReturnErrorOnFailure(ReadDerLength(reader, tag_len));
     759              : 
     760              :     // Length of sequence must match what is left of signature
     761          184 :     VerifyOrReturnError(tag_len == reader.Remaining(), CHIP_ERROR_INVALID_ARGUMENT);
     762              : 
     763              :     // Can now clear raw signature integers r,s one by one
     764          184 :     uint8_t * raw_cursor = out_raw_sig.data();
     765              : 
     766              :     // Read R
     767          184 :     ReturnErrorOnFailure(ReadDerUnsignedIntegerIntoRaw(reader, MutableByteSpan{ raw_cursor, fe_length_bytes }));
     768              : 
     769          184 :     raw_cursor += fe_length_bytes;
     770              : 
     771              :     // Read S
     772          184 :     ReturnErrorOnFailure(ReadDerUnsignedIntegerIntoRaw(reader, MutableByteSpan{ raw_cursor, fe_length_bytes }));
     773              : 
     774          184 :     out_raw_sig = out_raw_sig.SubSpan(0, (2u * fe_length_bytes));
     775              : 
     776          184 :     return CHIP_NO_ERROR;
     777              : }
     778              : 
     779           10 : CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const Aes128KeyHandle & key, const uint8_t * nonce,
     780              :                          size_t nonce_length, uint8_t * output)
     781              : {
     782              :     // Discard tag portion of CCM to apply only CTR mode encryption/decryption.
     783           10 :     constexpr size_t kTagLen = Crypto::kAES_CCM128_Tag_Length;
     784              :     uint8_t tag[kTagLen];
     785              : 
     786           10 :     return AES_CCM_encrypt(input, input_length, nullptr, 0, key, nonce, nonce_length, output, tag, kTagLen);
     787              : }
     788              : 
     789          797 : CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_key, uint64_t fabric_id,
     790              :                                       MutableByteSpan & out_compressed_fabric_id)
     791              : {
     792          797 :     VerifyOrReturnError(root_public_key.IsUncompressed(), CHIP_ERROR_INVALID_ARGUMENT);
     793          796 :     VerifyOrReturnError(out_compressed_fabric_id.size() >= kCompressedFabricIdentifierSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     794              : 
     795              :     // Ensure proper endianness for Fabric ID (i.e. big-endian as it appears in certificates)
     796              :     uint8_t fabric_id_as_big_endian_salt[kCompressedFabricIdentifierSize];
     797          795 :     chip::Encoding::BigEndian::Put64(&fabric_id_as_big_endian_salt[0], fabric_id);
     798              : 
     799              :     // Compute Compressed fabric reference per spec pseudocode
     800              :     //   CompressedFabricIdentifier =
     801              :     //     CHIP_Crypto_KDF(
     802              :     //       inputKey := TargetOperationalRootPublicKey,
     803              :     //       salt:= TargetOperationalFabricID,
     804              :     //       info := CompressedFabricInfo,
     805              :     //       len := 64)
     806              :     //
     807              :     // NOTE: len=64 bits is implied by output buffer size when calling HKDF_sha::HKDF_SHA256.
     808              : 
     809          795 :     constexpr uint8_t kCompressedFabricInfo[16] = /* "CompressedFabric" */
     810              :         { 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63 };
     811          795 :     HKDF_sha hkdf;
     812              : 
     813              :     // Must drop uncompressed point form format specifier (first byte), per spec method
     814          795 :     ByteSpan input_key_span(root_public_key.ConstBytes() + 1, root_public_key.Length() - 1);
     815              : 
     816          795 :     CHIP_ERROR status = hkdf.HKDF_SHA256(
     817              :         input_key_span.data(), input_key_span.size(), &fabric_id_as_big_endian_salt[0], sizeof(fabric_id_as_big_endian_salt),
     818              :         &kCompressedFabricInfo[0], sizeof(kCompressedFabricInfo), out_compressed_fabric_id.data(), kCompressedFabricIdentifierSize);
     819              : 
     820              :     // Resize output to final bounds on success
     821          795 :     if (status == CHIP_NO_ERROR)
     822              :     {
     823          795 :         out_compressed_fabric_id = out_compressed_fabric_id.SubSpan(0, kCompressedFabricIdentifierSize);
     824              :     }
     825              : 
     826          795 :     return status;
     827          795 : }
     828              : 
     829           11 : CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & rootPublicKey, uint64_t fabricId, uint64_t & compressedFabricId)
     830              : {
     831              :     uint8_t allocated[sizeof(fabricId)];
     832           11 :     MutableByteSpan span(allocated);
     833           11 :     ReturnErrorOnFailure(GenerateCompressedFabricId(rootPublicKey, fabricId, span));
     834              :     // Decode compressed fabric ID accounting for endianness, as GenerateCompressedFabricId()
     835              :     // returns a binary buffer and is agnostic of usage of the output as an integer type.
     836           11 :     compressedFabricId = Encoding::BigEndian::Get64(allocated);
     837           11 :     return CHIP_NO_ERROR;
     838              : }
     839              : 
     840              : /* Operational Group Key Group, Security Info: "GroupKey v1.0" */
     841              : static const uint8_t kGroupSecurityInfo[] = { 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x20, 0x76, 0x31, 0x2e, 0x30 };
     842              : 
     843              : /* Group Key Derivation Function, Info: "GroupKeyHash" ” */
     844              : static const uint8_t kGroupKeyHashInfo[]  = { 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x48, 0x61, 0x73, 0x68 };
     845              : static const uint8_t kGroupKeyHashSalt[0] = {};
     846              : 
     847              : /*
     848              :     OperationalGroupKey =
     849              :         Crypto_KDF
     850              :         (
     851              :             InputKey = Epoch Key,
     852              :             Salt = CompressedFabricIdentifier,
     853              :             Info = "GroupKey v1.0",
     854              :             Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS
     855              :         )
     856              : */
     857          200 : CHIP_ERROR DeriveGroupOperationalKey(const ByteSpan & epoch_key, const ByteSpan & compressed_fabric_id, MutableByteSpan & out_key)
     858              : {
     859          200 :     VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == epoch_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
     860          199 :     VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES <= out_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
     861              : 
     862          199 :     Crypto::HKDF_sha crypto;
     863          199 :     return crypto.HKDF_SHA256(epoch_key.data(), epoch_key.size(), compressed_fabric_id.data(), compressed_fabric_id.size(),
     864              :                               kGroupSecurityInfo, sizeof(kGroupSecurityInfo), out_key.data(),
     865          199 :                               Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
     866          199 : }
     867              : 
     868              : /*
     869              :     GKH = Crypto_KDF (
     870              :         InputKey = OperationalGroupKey,
     871              :         Salt = [],
     872              :         Info = "GroupKeyHash",
     873              :         Length = 16)
     874              : */
     875          199 : CHIP_ERROR DeriveGroupSessionId(const ByteSpan & operational_key, uint16_t & session_id)
     876              : {
     877          199 :     VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == operational_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
     878          198 :     Crypto::HKDF_sha crypto;
     879              :     uint8_t out_key[sizeof(uint16_t)];
     880              : 
     881          198 :     ReturnErrorOnFailure(crypto.HKDF_SHA256(operational_key.data(), operational_key.size(), kGroupKeyHashSalt,
     882              :                                             sizeof(kGroupKeyHashSalt), kGroupKeyHashInfo, sizeof(kGroupKeyHashInfo), out_key,
     883              :                                             sizeof(out_key)));
     884          198 :     session_id = Encoding::BigEndian::Get16(out_key);
     885          198 :     return CHIP_NO_ERROR;
     886          198 : }
     887              : 
     888              : /* Operational Group Key Group, PrivacyKey Info: "PrivacyKey" */
     889              : static const uint8_t kGroupPrivacyInfo[] = { 'P', 'r', 'i', 'v', 'a', 'c', 'y', 'K', 'e', 'y' };
     890              : 
     891              : /*
     892              :     PrivacyKey =
     893              :          Crypto_KDF
     894              :          (
     895              :             InputKey = EncryptionKey,
     896              :             Salt = [],
     897              :             Info = "PrivacyKey",
     898              :             Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS
     899              :          )
     900              : */
     901         1046 : CHIP_ERROR DeriveGroupPrivacyKey(const ByteSpan & encryption_key, MutableByteSpan & out_key)
     902              : {
     903         1046 :     VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == encryption_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
     904         1045 :     VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES <= out_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
     905              : 
     906         1045 :     constexpr ByteSpan null_span = ByteSpan();
     907              : 
     908         1045 :     Crypto::HKDF_sha crypto;
     909         1045 :     return crypto.HKDF_SHA256(encryption_key.data(), encryption_key.size(), null_span.data(), null_span.size(), kGroupPrivacyInfo,
     910         1045 :                               sizeof(kGroupPrivacyInfo), out_key.data(), Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
     911         1045 : }
     912              : 
     913          196 : CHIP_ERROR DeriveGroupOperationalCredentials(const ByteSpan & epoch_key, const ByteSpan & compressed_fabric_id,
     914              :                                              GroupOperationalCredentials & operational_credentials)
     915              : {
     916          196 :     MutableByteSpan encryption_key(operational_credentials.encryption_key);
     917          196 :     MutableByteSpan privacy_key(operational_credentials.privacy_key);
     918              : 
     919          196 :     ReturnErrorOnFailure(Crypto::DeriveGroupOperationalKey(epoch_key, compressed_fabric_id, encryption_key));
     920          196 :     ReturnErrorOnFailure(Crypto::DeriveGroupSessionId(encryption_key, operational_credentials.hash));
     921          196 :     ReturnErrorOnFailure(Crypto::DeriveGroupPrivacyKey(encryption_key, privacy_key));
     922              : 
     923          196 :     return CHIP_NO_ERROR;
     924              : }
     925              : 
     926            8 : CHIP_ERROR GenerateVendorFabricBindingMessage(FabricBindingVersion fabricBindingVersion, const P256PublicKey & rootPublicKey,
     927              :                                               FabricId fabricId, uint16_t vendorId, MutableByteSpan & outputSpan)
     928              : {
     929              :     // Only V1 supported yet.
     930            8 :     switch (fabricBindingVersion)
     931              :     {
     932            7 :     case FabricBindingVersion::kVersion1:
     933            7 :         break;
     934            1 :     default:
     935            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     936              :     }
     937              : 
     938            7 :     Encoding::BigEndian::BufferWriter writer(outputSpan);
     939              : 
     940              :     // vendor_fabric_binding_message := fabric_binding_version (1 byte) || root_public_key || fabric_id || vendor_id
     941            7 :     writer.Put8(to_underlying(fabricBindingVersion))
     942            7 :         .Put(rootPublicKey.ConstBytes(), rootPublicKey.Length())
     943            7 :         .Put64(fabricId)
     944            7 :         .Put16(vendorId);
     945              : 
     946            7 :     size_t actuallyWritten = 0;
     947            7 :     VerifyOrReturnError(writer.Fit(actuallyWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
     948              : 
     949            6 :     outputSpan.reduce_size(actuallyWritten);
     950            6 :     return CHIP_NO_ERROR;
     951              : }
     952              : 
     953           13 : CHIP_ERROR GenerateVendorIdVerificationToBeSigned(FabricIndex fabricIndex, const ByteSpan & clientChallenge,
     954              :                                                   const ByteSpan & attestationChallenge,
     955              :                                                   const ByteSpan & vendorFabricBindingMessage,
     956              :                                                   const ByteSpan & vidVerificationStatement, MutableByteSpan & outputSpan)
     957              : {
     958           13 :     VerifyOrReturnError((clientChallenge.size() == kVendorIdVerificationClientChallengeSize) &&
     959              :                             (attestationChallenge.size() == CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES) &&
     960              :                             !vendorFabricBindingMessage.empty(),
     961              :                         CHIP_ERROR_INVALID_ARGUMENT);
     962              : 
     963              :     // Extract binding version from vendorFabricBindingMessage. Only V1 supported yet.
     964            6 :     uint8_t fabricBindingVersion = vendorFabricBindingMessage[0];
     965            6 :     VerifyOrReturnError(fabricBindingVersion == to_underlying(FabricBindingVersion::kVersion1), CHIP_ERROR_INVALID_ARGUMENT);
     966              : 
     967            5 :     Encoding::BigEndian::BufferWriter writer(outputSpan);
     968              : 
     969              :     // vendor_id_verification_tbs := fabric_binding_version || client_challenge || attestation_challenge || fabric_index ||
     970              :     // vendor_fabric_binding_message || <vid_verification_statement>
     971            5 :     writer.Put8(fabricBindingVersion)
     972            5 :         .Put(clientChallenge.data(), clientChallenge.size())
     973            5 :         .Put(attestationChallenge.data(), attestationChallenge.size())
     974            5 :         .Put8(fabricIndex)
     975            5 :         .Put(vendorFabricBindingMessage.data(), vendorFabricBindingMessage.size())
     976            5 :         .Put(vidVerificationStatement.data(), vidVerificationStatement.size());
     977              : 
     978            5 :     size_t actuallyWritten = 0;
     979            5 :     VerifyOrReturnError(writer.Fit(actuallyWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
     980              : 
     981            4 :     outputSpan.reduce_size(actuallyWritten);
     982            4 :     return CHIP_NO_ERROR;
     983              : }
     984              : 
     985          825 : CHIP_ERROR ExtractVIDPIDFromAttributeString(DNAttrType attrType, const ByteSpan & attr,
     986              :                                             AttestationCertVidPid & vidpidFromMatterAttr, AttestationCertVidPid & vidpidFromCNAttr)
     987              : {
     988          825 :     VerifyOrReturnError(attrType != DNAttrType::kUnspecified, CHIP_NO_ERROR);
     989          824 :     VerifyOrReturnError(!attr.empty(), CHIP_ERROR_INVALID_ARGUMENT);
     990              : 
     991          823 :     if (attrType == DNAttrType::kMatterVID || attrType == DNAttrType::kMatterPID)
     992              :     {
     993              :         uint16_t matterAttr;
     994          482 :         VerifyOrReturnError(attr.size() == kVIDandPIDHexLength, CHIP_ERROR_WRONG_CERT_DN);
     995          472 :         VerifyOrReturnError(Encoding::UppercaseHexToUint16(reinterpret_cast<const char *>(attr.data()), attr.size(), matterAttr) ==
     996              :                                 sizeof(matterAttr),
     997              :                             CHIP_ERROR_WRONG_CERT_DN);
     998              : 
     999          468 :         if (attrType == DNAttrType::kMatterVID)
    1000              :         {
    1001              :             // Not more than one VID attribute can be present.
    1002          291 :             VerifyOrReturnError(!vidpidFromMatterAttr.mVendorId.HasValue(), CHIP_ERROR_WRONG_CERT_DN);
    1003          291 :             vidpidFromMatterAttr.mVendorId.SetValue(static_cast<VendorId>(matterAttr));
    1004              :         }
    1005              :         else
    1006              :         {
    1007              :             // Not more than one PID attribute can be present.
    1008          177 :             VerifyOrReturnError(!vidpidFromMatterAttr.mProductId.HasValue(), CHIP_ERROR_WRONG_CERT_DN);
    1009          177 :             vidpidFromMatterAttr.mProductId.SetValue(matterAttr);
    1010              :         }
    1011          468 :     }
    1012              :     // Otherwise, it is a CommonName attribute.
    1013          345 :     else if (!vidpidFromCNAttr.Initialized())
    1014              :     {
    1015          345 :         ByteSpan attr_source_span{ attr };
    1016          345 :         if (attr_source_span.size() > chip::Crypto::kMax_CommonNameAttr_Length)
    1017              :         {
    1018            0 :             attr_source_span.reduce_size(chip::Crypto::kMax_CommonNameAttr_Length);
    1019              :         }
    1020              : 
    1021              :         // Try to find a valid Vendor ID encoded in fallback method.
    1022          345 :         uint16_t vid   = 0;
    1023          345 :         CHIP_ERROR err = Find16BitUpperCaseHexAfterPrefix(attr_source_span, kVIDPrefixForCNEncoding, vid);
    1024          345 :         if (err == CHIP_NO_ERROR)
    1025              :         {
    1026           41 :             vidpidFromCNAttr.mVendorId.SetValue(static_cast<VendorId>(vid));
    1027              :         }
    1028          304 :         else if (err != CHIP_ERROR_NOT_FOUND)
    1029              :         {
    1030              :             // This indicates a bad/ambiguous format.
    1031           20 :             return err;
    1032              :         }
    1033              : 
    1034              :         // Try to find a valid Product ID encoded in fallback method.
    1035          334 :         uint16_t pid = 0;
    1036          334 :         err          = Find16BitUpperCaseHexAfterPrefix(attr_source_span, kPIDPrefixForCNEncoding, pid);
    1037          334 :         if (err == CHIP_NO_ERROR)
    1038              :         {
    1039           31 :             vidpidFromCNAttr.mProductId.SetValue(pid);
    1040              :         }
    1041          303 :         else if (err != CHIP_ERROR_NOT_FOUND)
    1042              :         {
    1043              :             // This indicates a bad/ambiguous format.
    1044            9 :             return err;
    1045              :         }
    1046              :     }
    1047              : 
    1048          793 :     return CHIP_NO_ERROR;
    1049              : }
    1050              : 
    1051              : // Generates the to-be-signed portion of a PKCS#10 CSR (`CertificationRequestInformation`)
    1052              : // that contains the
    1053            2 : static CHIP_ERROR GenerateCertificationRequestInformation(ASN1Writer & writer, const Crypto::P256PublicKey & pubkey)
    1054              : {
    1055            2 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1056              :     /**
    1057              :      *
    1058              :      *  CertificationRequestInfo ::=
    1059              :      *     SEQUENCE {
    1060              :      *        version       INTEGER { v1(0) } (v1,...),
    1061              :      *        subject       Name,
    1062              :      *        subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
    1063              :      *        attributes    [0] Attributes{{ CRIAttributes }}
    1064              :      * }
    1065              :      */
    1066            2 :     ASN1_START_SEQUENCE
    1067              :     {
    1068            2 :         ASN1_ENCODE_INTEGER(0); // version INTEGER { v1(0) }
    1069              : 
    1070              :         // subject Name
    1071            2 :         ASN1_START_SEQUENCE
    1072              :         {
    1073            2 :             ASN1_START_SET
    1074              :             {
    1075            2 :                 ASN1_START_SEQUENCE
    1076              :                 {
    1077              :                     // Any subject, placeholder is good, since this
    1078              :                     // is going to usually be ignored
    1079            2 :                     ASN1_ENCODE_OBJECT_ID(kOID_AttributeType_OrganizationalUnitName);
    1080            2 :                     ASN1_ENCODE_STRING(kASN1UniversalTag_UTF8String, "CSA", static_cast<uint16_t>(strlen("CSA")));
    1081              :                 }
    1082            2 :                 ASN1_END_SEQUENCE;
    1083              :             }
    1084            2 :             ASN1_END_SET;
    1085              :         }
    1086            2 :         ASN1_END_SEQUENCE;
    1087              : 
    1088              :         // subjectPKInfo
    1089            2 :         ASN1_START_SEQUENCE
    1090              :         {
    1091            2 :             ASN1_START_SEQUENCE
    1092              :             {
    1093            2 :                 ASN1_ENCODE_OBJECT_ID(kOID_PubKeyAlgo_ECPublicKey);
    1094            2 :                 ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
    1095              :             }
    1096            2 :             ASN1_END_SEQUENCE;
    1097            2 :             ReturnErrorOnFailure(writer.PutBitString(0, pubkey, static_cast<uint8_t>(pubkey.Length())));
    1098              :         }
    1099            2 :         ASN1_END_SEQUENCE;
    1100              : 
    1101              :         // attributes [0]
    1102            2 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
    1103              :         {
    1104              :             // Using a plain empty attributes request
    1105            2 :             ASN1_START_SEQUENCE
    1106              :             {
    1107            2 :                 ASN1_ENCODE_OBJECT_ID(kOID_Extension_CSRRequest);
    1108            2 :                 ASN1_START_SET
    1109              :                 {
    1110            2 :                     ASN1_START_SEQUENCE {}
    1111            2 :                     ASN1_END_SEQUENCE;
    1112              :                 }
    1113            2 :                 ASN1_END_SET;
    1114              :             }
    1115            2 :             ASN1_END_SEQUENCE;
    1116              :         }
    1117            2 :         ASN1_END_CONSTRUCTED;
    1118              :     }
    1119            2 :     ASN1_END_SEQUENCE;
    1120            2 : exit:
    1121            2 :     return err;
    1122              : }
    1123              : 
    1124            3 : CHIP_ERROR GenerateCertificateSigningRequest(const P256Keypair * keypair, MutableByteSpan & csr_span)
    1125              : {
    1126            3 :     VerifyOrReturnError(keypair != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1127            2 :     VerifyOrReturnError(csr_span.size() >= kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL);
    1128              : 
    1129              :     // First pass: Generate the CertificatioRequestInformation inner
    1130              :     // encoding one time, to sign it, before re-generating it within the
    1131              :     // full ASN1 writer later, since it's easier than trying to
    1132              :     // figure-out the span we need to sign of the overall object.
    1133            1 :     P256ECDSASignature signature;
    1134              : 
    1135              :     {
    1136              :         // The first pass will just generate a signature, so we can use the
    1137              :         // output buffer as scratch to avoid needing more stack space. There
    1138              :         // are no secrets here and the contents is not reused since all we
    1139              :         // need is the signature which is already separately stored.
    1140              :         ASN1Writer toBeSignedWriter;
    1141            1 :         toBeSignedWriter.Init(csr_span);
    1142            1 :         CHIP_ERROR err = GenerateCertificationRequestInformation(toBeSignedWriter, keypair->Pubkey());
    1143            1 :         ReturnErrorOnFailure(err);
    1144              : 
    1145            1 :         size_t encodedLen = (uint16_t) toBeSignedWriter.GetLengthWritten();
    1146              :         // This should not/will not happen
    1147            1 :         if (encodedLen > csr_span.size())
    1148              :         {
    1149            0 :             return CHIP_ERROR_INTERNAL;
    1150              :         }
    1151              : 
    1152            1 :         err = keypair->ECDSA_sign_msg(csr_span.data(), encodedLen, signature);
    1153            1 :         ReturnErrorOnFailure(err);
    1154              :     }
    1155              : 
    1156              :     // Second pass: Generate the entire CSR body, restarting a new write
    1157              :     // of the CertificationRequestInformation (cheap) and adding the
    1158              :     // signature.
    1159              :     //
    1160              :     // See RFC2986 for ASN.1 module, repeated here in snippets
    1161            1 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1162              : 
    1163              :     ASN1Writer writer;
    1164            1 :     writer.Init(csr_span);
    1165              : 
    1166            1 :     ASN1_START_SEQUENCE
    1167              :     {
    1168              : 
    1169              :         /*  CertificationRequestInfo ::=
    1170              :          *     SEQUENCE {
    1171              :          *        version       INTEGER { v1(0) } (v1,...),
    1172              :          *        subject       Name,
    1173              :          *        subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
    1174              :          *        attributes    [0] Attributes{{ CRIAttributes }}
    1175              :          *     }
    1176              :          */
    1177            1 :         GenerateCertificationRequestInformation(writer, keypair->Pubkey());
    1178              : 
    1179              :         // algorithm  AlgorithmIdentifier
    1180            1 :         ASN1_START_SEQUENCE
    1181              :         {
    1182              :             // See RFC5480 sec 2.1
    1183            1 :             ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
    1184              :         }
    1185            1 :         ASN1_END_SEQUENCE;
    1186              : 
    1187              :         // signature  BIT STRING --> ECDSA-with-SHA256 signature with P256 key with R,S integers format
    1188              :         // (see RFC3279 sec 2.2.3 ECDSA Signature Algorithm)
    1189            1 :         ASN1_START_BIT_STRING_ENCAPSULATED
    1190              :         {
    1191              :             // Convert raw signature to embedded signature
    1192            1 :             FixedByteSpan<Crypto::kP256_ECDSA_Signature_Length_Raw> rawSig(signature.Bytes());
    1193              : 
    1194              :             uint8_t derInt[kP256_FE_Length + kEmitDerIntegerWithoutTagOverhead];
    1195              : 
    1196              :             // Ecdsa-Sig-Value ::= SEQUENCE
    1197            1 :             ASN1_START_SEQUENCE
    1198              :             {
    1199              :                 using P256IntegerSpan = FixedByteSpan<Crypto::kP256_FE_Length>;
    1200              :                 // r INTEGER
    1201              :                 {
    1202            1 :                     MutableByteSpan derIntSpan(derInt, sizeof(derInt));
    1203            1 :                     ReturnErrorOnFailure(ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data()), derIntSpan));
    1204            1 :                     ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false,
    1205              :                                                          derIntSpan.data(), static_cast<uint16_t>(derIntSpan.size())));
    1206              :                 }
    1207              : 
    1208              :                 // s INTEGER
    1209              :                 {
    1210            1 :                     MutableByteSpan derIntSpan(derInt, sizeof(derInt));
    1211            1 :                     ReturnErrorOnFailure(
    1212              :                         ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data() + kP256_FE_Length), derIntSpan));
    1213            1 :                     ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false,
    1214              :                                                          derIntSpan.data(), static_cast<uint16_t>(derIntSpan.size())));
    1215              :                 }
    1216              :             }
    1217            1 :             ASN1_END_SEQUENCE;
    1218              :         }
    1219            1 :         ASN1_END_ENCAPSULATED;
    1220              :     }
    1221            1 :     ASN1_END_SEQUENCE;
    1222              : 
    1223            1 : exit:
    1224              :     // Update size of output buffer on success
    1225            1 :     if (err == CHIP_NO_ERROR)
    1226              :     {
    1227            1 :         csr_span.reduce_size(writer.GetLengthWritten());
    1228              :     }
    1229            1 :     return err;
    1230            1 : }
    1231              : 
    1232           60 : CHIP_ERROR VerifyCertificateSigningRequestFormat(const uint8_t * csr, size_t csr_length)
    1233              : {
    1234              :     // Ensure we have enough size to validate header, and that our assumptions are met
    1235              :     // for some tag computations below. A csr_length > 65535 would never be seen in
    1236              :     // practice.
    1237           60 :     VerifyOrReturnError((csr_length >= 16) && (csr_length <= 65535), CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
    1238              : 
    1239           58 :     Reader reader(csr, csr_length);
    1240              : 
    1241              :     // Ensure we have an outermost SEQUENCE
    1242           58 :     uint8_t seq_header = 0;
    1243           58 :     ReturnErrorOnFailure(reader.Read8(&seq_header).StatusCode());
    1244           58 :     VerifyOrReturnError(seq_header == kSeqTag, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
    1245              : 
    1246           56 :     size_t seq_length = 0;
    1247           56 :     VerifyOrReturnError(ReadDerLength(reader, seq_length) == CHIP_NO_ERROR, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
    1248              :     // Ensure that outer length matches sequence length + tag overhead, otherwise
    1249              :     // we have trailing garbage
    1250           56 :     size_t header_overhead = (seq_length <= 127) ? 2 : ((seq_length <= 255) ? 3 : 4);
    1251           56 :     VerifyOrReturnError(csr_length == (seq_length + header_overhead), CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
    1252              : 
    1253           52 :     return CHIP_NO_ERROR;
    1254              : }
    1255              : 
    1256              : } // namespace Crypto
    1257              : } // namespace chip
        

Generated by: LCOV version 2.0-1