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 135653 : 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 135604 : static uint32_t GetDefaultInitialValuePredecessor() { return Crypto::GetRandU32() & kMessageCounterRandomInitMask; }
58 : };
59 :
60 : class GlobalUnencryptedMessageCounter : public MessageCounter
61 : {
62 : public:
63 419 : GlobalUnencryptedMessageCounter() : mLastUsedValue(0) {}
64 :
65 370 : 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 135234 : LocalSessionMessageCounter() { mLastUsedValue = GetDefaultInitialValuePredecessor(); }
91 :
92 0 : Type GetType() const override { return Session; }
93 9725 : CHIP_ERROR AdvanceAndConsume(uint32_t & fetch) override
94 : {
95 9725 : if (mLastUsedValue == kMessageCounterMax)
96 : {
97 1 : return CHIP_ERROR_MESSAGE_COUNTER_EXHAUSTED;
98 : }
99 :
100 9724 : fetch = ++mLastUsedValue;
101 9724 : 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
|