Line data Source code
1 : /* 2 : * Copyright (c) 2021 Project CHIP Authors 3 : * 4 : * Licensed under the Apache License, Version 2.0 (the "License"); 5 : * you may not use this file except in compliance with the License. 6 : * You may obtain a copy of the License at 7 : * 8 : * http://www.apache.org/licenses/LICENSE-2.0 9 : * 10 : * Unless required by applicable law or agreed to in writing, software 11 : * distributed under the License is distributed on an "AS IS" BASIS, 12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : * See the License for the specific language governing permissions and 14 : * limitations under the License. 15 : */ 16 : 17 : /** 18 : * @file 19 : * This file defines the CHIP message counters. 20 : * 21 : */ 22 : #pragma once 23 : 24 : #include <crypto/RandUtils.h> 25 : #include <lib/core/CHIPError.h> 26 : 27 : #include <stdint.h> 28 : 29 : namespace chip { 30 : 31 : /** 32 : * MessageCounter represents a local message counter. There are 2 types of message counter 33 : * 34 : * 1. Global unencrypted message counter 35 : * 2. Secure session message counter 36 : * 37 : * There will be separate implementations for each type 38 : */ 39 : class MessageCounter 40 : { 41 : public: 42 : static constexpr uint32_t kMessageCounterRandomInitMask = 0x0FFFFFFF; ///< 28-bit mask 43 : 44 : enum Type : uint8_t 45 : { 46 : GlobalUnencrypted, 47 : GlobalEncrypted, 48 : Session, 49 : }; 50 : 51 135192 : virtual ~MessageCounter() = default; 52 : 53 : virtual Type GetType() const = 0; 54 : virtual CHIP_ERROR AdvanceAndConsume(uint32_t & fetch) = 0; /** Advance the counter, and feed the new counter to fetch */ 55 : 56 : // Note: this function must be called after Crypto is initialized. It can not be called from global variable constructor. 57 135425 : static uint32_t GetDefaultInitialValuePredecessor() { return Crypto::GetRandU32() & kMessageCounterRandomInitMask; } 58 : }; 59 : 60 : class GlobalUnencryptedMessageCounter : public MessageCounter 61 : { 62 : public: 63 101 : GlobalUnencryptedMessageCounter() : mLastUsedValue(0) {} 64 : 65 334 : void Init() { mLastUsedValue = GetDefaultInitialValuePredecessor(); } 66 : 67 0 : Type GetType() const override { return GlobalUnencrypted; } 68 98 : CHIP_ERROR AdvanceAndConsume(uint32_t & fetch) override 69 : { 70 98 : fetch = ++mLastUsedValue; 71 98 : return CHIP_NO_ERROR; 72 : } 73 : 74 : private: 75 : uint32_t mLastUsedValue; 76 : }; 77 : 78 : class LocalSessionMessageCounter : public MessageCounter 79 : { 80 : public: 81 : static constexpr uint32_t kMessageCounterMax = 0xFFFFFFFF; 82 : 83 : /** 84 : * Initialize a local message counter with random value between [1, 2^28]. This increases the difficulty of traffic analysis 85 : * attacks by making it harder to determine how long a particular session has been open. The initial counter is always 1 or 86 : * higher to guarantee first message is always greater than initial peer counter set to 0. 87 : * 88 : * The mLastUsedValue is the predecessor of the initial value, it will be advanced before using, so don't need to add 1 here. 89 : */ 90 135091 : LocalSessionMessageCounter() { mLastUsedValue = GetDefaultInitialValuePredecessor(); } 91 : 92 0 : Type GetType() const override { return Session; } 93 9488 : CHIP_ERROR AdvanceAndConsume(uint32_t & fetch) override 94 : { 95 9488 : if (mLastUsedValue == kMessageCounterMax) 96 : { 97 1 : return CHIP_ERROR_MESSAGE_COUNTER_EXHAUSTED; 98 : } 99 : 100 9487 : fetch = ++mLastUsedValue; 101 9487 : return CHIP_NO_ERROR; 102 : } 103 : 104 : // Test-only function to set the counter value 105 : void TestSetCounter(uint32_t value) { mLastUsedValue = value; } 106 : 107 : private: 108 : uint32_t mLastUsedValue; 109 : }; 110 : 111 : } // namespace chip