LCOV - code coverage report
Current view: top level - crypto - CHIPCryptoPAL.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 489 514 95.1 %
Date: 2024-02-15 08:20:41 Functions: 37 39 94.9 %

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

Generated by: LCOV version 1.14