Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CheckinMessage.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 55 55
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2020 Project CHIP Authors
       3              :  *    All rights reserved.
       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              :  *      This file implements the Matter Checkin protocol.
      21              :  */
      22              : 
      23              : #include <lib/core/CHIPCore.h>
      24              : #include <lib/core/CHIPEncoding.h>
      25              : #include <protocols/secure_channel/CheckinMessage.h>
      26              : #include <protocols/secure_channel/Constants.h>
      27              : 
      28              : using namespace chip::Crypto;
      29              : 
      30              : namespace chip {
      31              : namespace Protocols {
      32              : namespace SecureChannel {
      33              : 
      34           26 : CHIP_ERROR CheckinMessage::GenerateCheckinMessagePayload(const Crypto::Aes128KeyHandle & aes128KeyHandle,
      35              :                                                          const Crypto::Hmac128KeyHandle & hmacKeyHandle,
      36              :                                                          const CounterType & counter, const ByteSpan & appData,
      37              :                                                          MutableByteSpan & output)
      38              : {
      39           26 :     VerifyOrReturnError(output.size() >= (appData.size() + kMinPayloadSize), CHIP_ERROR_BUFFER_TOO_SMALL);
      40           25 :     size_t cursorIndex = 0;
      41              : 
      42              :     // Generate Nonce from Key and counter value
      43              :     {
      44           25 :         MutableByteSpan nonce = output.SubSpan(0, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
      45           25 :         cursorIndex += nonce.size();
      46              : 
      47           25 :         Encoding::LittleEndian::BufferWriter writer(nonce);
      48           25 :         ReturnErrorOnFailure(GenerateCheckInMessageNonce(hmacKeyHandle, counter, writer));
      49              :     }
      50              : 
      51              :     // Encrypt Counter and Application Data
      52              :     {
      53           25 :         MutableByteSpan payloadByteSpan = output.SubSpan(cursorIndex, sizeof(CounterType) + appData.size());
      54           25 :         cursorIndex += payloadByteSpan.size();
      55              : 
      56           25 :         Encoding::LittleEndian::BufferWriter payloadWriter(payloadByteSpan);
      57              : 
      58           25 :         payloadWriter.EndianPut(counter, sizeof(counter));
      59           25 :         payloadWriter.Put(appData.data(), appData.size());
      60           25 :         VerifyOrReturnError(payloadWriter.Fit(), CHIP_ERROR_INTERNAL);
      61              : 
      62           25 :         MutableByteSpan mic = output.SubSpan(cursorIndex, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
      63           25 :         cursorIndex += mic.size();
      64              : 
      65              :         // Validate that the cursorIndex is within the available output space
      66           25 :         VerifyOrReturnError(cursorIndex <= output.size(), CHIP_ERROR_BUFFER_TOO_SMALL);
      67              :         // Validate that the cursorIndex matchs the message length
      68           25 :         VerifyOrReturnError(cursorIndex == appData.size() + kMinPayloadSize, CHIP_ERROR_INTERNAL);
      69              : 
      70           25 :         ReturnErrorOnFailure(Crypto::AES_CCM_encrypt(payloadByteSpan.data(), payloadByteSpan.size(), nullptr, 0, aes128KeyHandle,
      71              :                                                      output.data(), CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, payloadByteSpan.data(),
      72              :                                                      mic.data(), mic.size()));
      73              :     }
      74              : 
      75           25 :     output.reduce_size(appData.size() + kMinPayloadSize);
      76           25 :     return CHIP_NO_ERROR;
      77              : }
      78              : 
      79           33 : CHIP_ERROR CheckinMessage::ParseCheckinMessagePayload(const Crypto::Aes128KeyHandle & aes128KeyHandle,
      80              :                                                       const Crypto::Hmac128KeyHandle & hmacKeyHandle, const ByteSpan & payload,
      81              :                                                       CounterType & counter, MutableByteSpan & appData)
      82              : {
      83           33 :     size_t appDataSize = GetAppDataSize(payload);
      84              : 
      85           33 :     VerifyOrReturnError(payload.size() >= kMinPayloadSize, CHIP_ERROR_INVALID_MESSAGE_LENGTH);
      86              :     // To prevent workbuffer usage, appData size needs to be large enough to hold both the appData and the counter
      87           33 :     VerifyOrReturnError(appData.size() >= sizeof(CounterType) + appDataSize, CHIP_ERROR_BUFFER_TOO_SMALL);
      88              : 
      89              :     // Decrypt received data
      90              :     {
      91           32 :         size_t cursorIndex = 0;
      92              : 
      93           32 :         ByteSpan nonce = payload.SubSpan(cursorIndex, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
      94           32 :         cursorIndex += nonce.size();
      95              : 
      96           32 :         ByteSpan encryptedData = payload.SubSpan(cursorIndex, sizeof(CounterType) + appDataSize);
      97           32 :         cursorIndex += encryptedData.size();
      98              : 
      99           32 :         ByteSpan mic = payload.SubSpan(cursorIndex, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
     100           32 :         cursorIndex += mic.size();
     101              : 
     102              :         // Return Invalid message length since the payload isn't the right size
     103           43 :         VerifyOrReturnError(cursorIndex == payload.size(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     104              : 
     105           32 :         ReturnErrorOnFailure(Crypto::AES_CCM_decrypt(encryptedData.data(), encryptedData.size(), nullptr, 0, mic.data(), mic.size(),
     106              :                                                      aes128KeyHandle, nonce.data(), nonce.size(), appData.data()));
     107              :     }
     108              : 
     109              :     // Read decrypted counter and application data
     110              :     static_assert(sizeof(CounterType) == sizeof(uint32_t), "Expect counter to be 32 bits for correct decoding");
     111           21 :     CounterType tempCounter = Encoding::LittleEndian::Get32(appData.data());
     112              : 
     113              :     // Validate that the received nonce is correct
     114              :     {
     115           21 :         uint8_t calculatedNonceBuffer[CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES] = { 0 };
     116           21 :         Encoding::LittleEndian::BufferWriter writer(calculatedNonceBuffer, sizeof(calculatedNonceBuffer));
     117              : 
     118           21 :         ReturnErrorOnFailure(GenerateCheckInMessageNonce(hmacKeyHandle, tempCounter, writer));
     119              : 
     120              :         // Validate received nonce is the same as the calculated
     121           21 :         ByteSpan nonce = payload.SubSpan(0, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
     122           21 :         VerifyOrReturnError(memcmp(nonce.data(), calculatedNonceBuffer, sizeof(calculatedNonceBuffer)) == 0, CHIP_ERROR_INTERNAL);
     123              :     }
     124              : 
     125              :     // We have successfully decrypted and validated Check-In message
     126              :     // Set output values
     127              : 
     128           21 :     counter = tempCounter;
     129              :     // Shift to remove the counter from the appData
     130           21 :     memmove(appData.data(), sizeof(CounterType) + appData.data(), appDataSize);
     131           21 :     appData.reduce_size(appDataSize);
     132              : 
     133           21 :     return CHIP_NO_ERROR;
     134              : }
     135              : 
     136           46 : CHIP_ERROR CheckinMessage::GenerateCheckInMessageNonce(const Crypto::Hmac128KeyHandle & hmacKeyHandle, CounterType counter,
     137              :                                                        Encoding::LittleEndian::BufferWriter & writer)
     138              : {
     139           46 :     VerifyOrReturnError(writer.Available() >= CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
     140              : 
     141           46 :     uint8_t hashWorkBuffer[CHIP_CRYPTO_HASH_LEN_BYTES] = { 0 };
     142              :     uint8_t counterBuffer[sizeof(CounterType)];
     143              : 
     144              :     // validate that Check-In counter is a uint32_t
     145              :     static_assert(sizeof(CounterType) == sizeof(uint32_t), "Expect counter to be 32 bits for correct encoding");
     146           46 :     Encoding::LittleEndian::Put32(counterBuffer, counter);
     147              : 
     148           46 :     chip::Crypto::HMAC_sha shaHandler;
     149           46 :     ReturnErrorOnFailure(
     150              :         shaHandler.HMAC_SHA256(hmacKeyHandle, counterBuffer, sizeof(CounterType), hashWorkBuffer, CHIP_CRYPTO_HASH_LEN_BYTES));
     151              : 
     152           46 :     writer.Put(hashWorkBuffer, CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES);
     153           46 :     VerifyOrReturnError(writer.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
     154              : 
     155           46 :     return CHIP_NO_ERROR;
     156           46 : }
     157              : 
     158           39 : size_t CheckinMessage::GetAppDataSize(const ByteSpan & payload)
     159              : {
     160           39 :     return (payload.size() <= kMinPayloadSize) ? 0 : payload.size() - kMinPayloadSize;
     161              : }
     162              : 
     163              : } // namespace SecureChannel
     164              : } // namespace Protocols
     165              : } // namespace chip
        

Generated by: LCOV version 2.0-1