1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements Thread security material generation.
32 */
33
34 #include "key_manager.hpp"
35
36 #include "common/code_utils.hpp"
37 #include "common/encoding.hpp"
38 #include "common/instance.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/timer.hpp"
41 #include "crypto/hkdf_sha256.hpp"
42 #include "thread/mle_router.hpp"
43 #include "thread/thread_netif.hpp"
44
45 namespace ot {
46
47 const uint8_t KeyManager::kThreadString[] = {
48 'T', 'h', 'r', 'e', 'a', 'd',
49 };
50
51 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
52 const uint8_t KeyManager::kHkdfExtractSaltString[] = {'T', 'h', 'r', 'e', 'a', 'd', 'S', 'e', 'q', 'u', 'e', 'n',
53 'c', 'e', 'M', 'a', 's', 't', 'e', 'r', 'K', 'e', 'y'};
54
55 const uint8_t KeyManager::kTrelInfoString[] = {'T', 'h', 'r', 'e', 'a', 'd', 'O', 'v', 'e',
56 'r', 'I', 'n', 'f', 'r', 'a', 'K', 'e', 'y'};
57 #endif
58
SetToDefault(void)59 void SecurityPolicy::SetToDefault(void)
60 {
61 mRotationTime = kDefaultKeyRotationTime;
62 SetToDefaultFlags();
63 }
64
SetToDefaultFlags(void)65 void SecurityPolicy::SetToDefaultFlags(void)
66 {
67 mObtainNetworkKeyEnabled = true;
68 mNativeCommissioningEnabled = true;
69 mRoutersEnabled = true;
70 mExternalCommissioningEnabled = true;
71 mBeaconsEnabled = true;
72 mCommercialCommissioningEnabled = false;
73 mAutonomousEnrollmentEnabled = false;
74 mNetworkKeyProvisioningEnabled = false;
75 mTobleLinkEnabled = true;
76 mNonCcmRoutersEnabled = false;
77 mVersionThresholdForRouting = 0;
78 }
79
SetFlags(const uint8_t * aFlags,uint8_t aFlagsLength)80 void SecurityPolicy::SetFlags(const uint8_t *aFlags, uint8_t aFlagsLength)
81 {
82 OT_ASSERT(aFlagsLength > 0);
83
84 SetToDefaultFlags();
85
86 mObtainNetworkKeyEnabled = aFlags[0] & kObtainNetworkKeyMask;
87 mNativeCommissioningEnabled = aFlags[0] & kNativeCommissioningMask;
88 mRoutersEnabled = aFlags[0] & kRoutersMask;
89 mExternalCommissioningEnabled = aFlags[0] & kExternalCommissioningMask;
90 mBeaconsEnabled = aFlags[0] & kBeaconsMask;
91 mCommercialCommissioningEnabled = (aFlags[0] & kCommercialCommissioningMask) == 0;
92 mAutonomousEnrollmentEnabled = (aFlags[0] & kAutonomousEnrollmentMask) == 0;
93 mNetworkKeyProvisioningEnabled = (aFlags[0] & kNetworkKeyProvisioningMask) == 0;
94
95 VerifyOrExit(aFlagsLength > sizeof(aFlags[0]));
96 mTobleLinkEnabled = aFlags[1] & kTobleLinkMask;
97 mNonCcmRoutersEnabled = (aFlags[1] & kNonCcmRoutersMask) == 0;
98 mVersionThresholdForRouting = aFlags[1] & kVersionThresholdForRoutingMask;
99
100 exit:
101 return;
102 }
103
GetFlags(uint8_t * aFlags,uint8_t aFlagsLength) const104 void SecurityPolicy::GetFlags(uint8_t *aFlags, uint8_t aFlagsLength) const
105 {
106 OT_ASSERT(aFlagsLength > 0);
107
108 memset(aFlags, 0, aFlagsLength);
109
110 if (mObtainNetworkKeyEnabled)
111 {
112 aFlags[0] |= kObtainNetworkKeyMask;
113 }
114
115 if (mNativeCommissioningEnabled)
116 {
117 aFlags[0] |= kNativeCommissioningMask;
118 }
119
120 if (mRoutersEnabled)
121 {
122 aFlags[0] |= kRoutersMask;
123 }
124
125 if (mExternalCommissioningEnabled)
126 {
127 aFlags[0] |= kExternalCommissioningMask;
128 }
129
130 if (mBeaconsEnabled)
131 {
132 aFlags[0] |= kBeaconsMask;
133 }
134
135 if (!mCommercialCommissioningEnabled)
136 {
137 aFlags[0] |= kCommercialCommissioningMask;
138 }
139
140 if (!mAutonomousEnrollmentEnabled)
141 {
142 aFlags[0] |= kAutonomousEnrollmentMask;
143 }
144
145 if (!mNetworkKeyProvisioningEnabled)
146 {
147 aFlags[0] |= kNetworkKeyProvisioningMask;
148 }
149
150 VerifyOrExit(aFlagsLength > sizeof(aFlags[0]));
151
152 if (mTobleLinkEnabled)
153 {
154 aFlags[1] |= kTobleLinkMask;
155 }
156
157 if (!mNonCcmRoutersEnabled)
158 {
159 aFlags[1] |= kNonCcmRoutersMask;
160 }
161
162 aFlags[1] |= kReservedMask;
163 aFlags[1] |= mVersionThresholdForRouting;
164
165 exit:
166 return;
167 }
168
KeyManager(Instance & aInstance)169 KeyManager::KeyManager(Instance &aInstance)
170 : InstanceLocator(aInstance)
171 , mKeySequence(0)
172 , mMleFrameCounter(0)
173 , mStoredMacFrameCounter(0)
174 , mStoredMleFrameCounter(0)
175 , mHoursSinceKeyRotation(0)
176 , mKeySwitchGuardTime(kDefaultKeySwitchGuardTime)
177 , mKeySwitchGuardEnabled(false)
178 , mKeyRotationTimer(aInstance, KeyManager::HandleKeyRotationTimer)
179 , mKekFrameCounter(0)
180 , mIsPskcSet(false)
181 {
182 Error error = mNetworkKey.GenerateRandom();
183
184 OT_ASSERT(error == kErrorNone);
185 OT_UNUSED_VARIABLE(error);
186
187 mMacFrameCounters.Reset();
188 mPskc.Clear();
189 }
190
Start(void)191 void KeyManager::Start(void)
192 {
193 mKeySwitchGuardEnabled = false;
194 StartKeyRotationTimer();
195 }
196
Stop(void)197 void KeyManager::Stop(void)
198 {
199 mKeyRotationTimer.Stop();
200 }
201
202 #if OPENTHREAD_MTD || OPENTHREAD_FTD
SetPskc(const Pskc & aPskc)203 void KeyManager::SetPskc(const Pskc &aPskc)
204 {
205 IgnoreError(Get<Notifier>().Update(mPskc, aPskc, kEventPskcChanged));
206 mIsPskcSet = true;
207 }
208 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD
209
SetNetworkKey(const NetworkKey & aKey)210 Error KeyManager::SetNetworkKey(const NetworkKey &aKey)
211 {
212 Error error = kErrorNone;
213 Router *parent;
214
215 SuccessOrExit(Get<Notifier>().Update(mNetworkKey, aKey, kEventNetworkKeyChanged));
216 Get<Notifier>().Signal(kEventThreadKeySeqCounterChanged);
217 mKeySequence = 0;
218 UpdateKeyMaterial();
219
220 // reset parent frame counters
221 parent = &Get<Mle::MleRouter>().GetParent();
222 parent->SetKeySequence(0);
223 parent->GetLinkFrameCounters().Reset();
224 parent->SetLinkAckFrameCounter(0);
225 parent->SetMleFrameCounter(0);
226
227 #if OPENTHREAD_FTD
228 // reset router frame counters
229 for (Router &router : Get<RouterTable>().Iterate())
230 {
231 router.SetKeySequence(0);
232 router.GetLinkFrameCounters().Reset();
233 router.SetLinkAckFrameCounter(0);
234 router.SetMleFrameCounter(0);
235 }
236
237 // reset child frame counters
238 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
239 {
240 child.SetKeySequence(0);
241 child.GetLinkFrameCounters().Reset();
242 child.SetLinkAckFrameCounter(0);
243 child.SetMleFrameCounter(0);
244 }
245 #endif
246
247 exit:
248 return error;
249 }
250
ComputeKeys(uint32_t aKeySequence,HashKeys & aHashKeys)251 void KeyManager::ComputeKeys(uint32_t aKeySequence, HashKeys &aHashKeys)
252 {
253 Crypto::HmacSha256 hmac;
254 uint8_t keySequenceBytes[sizeof(uint32_t)];
255
256 hmac.Start(mNetworkKey.m8, sizeof(mNetworkKey.m8));
257
258 Encoding::BigEndian::WriteUint32(aKeySequence, keySequenceBytes);
259 hmac.Update(keySequenceBytes);
260 hmac.Update(kThreadString);
261
262 hmac.Finish(aHashKeys.mHash);
263 }
264
265 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
ComputeTrelKey(uint32_t aKeySequence,Mac::Key & aTrelKey)266 void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aTrelKey)
267 {
268 Crypto::HkdfSha256 hkdf;
269 uint8_t salt[sizeof(uint32_t) + sizeof(kHkdfExtractSaltString)];
270
271 Encoding::BigEndian::WriteUint32(aKeySequence, salt);
272 memcpy(salt + sizeof(uint32_t), kHkdfExtractSaltString, sizeof(kHkdfExtractSaltString));
273
274 hkdf.Extract(salt, sizeof(salt), mNetworkKey.m8, sizeof(NetworkKey));
275 hkdf.Expand(kTrelInfoString, sizeof(kTrelInfoString), aTrelKey.m8, sizeof(Mac::Key));
276 }
277 #endif
278
UpdateKeyMaterial(void)279 void KeyManager::UpdateKeyMaterial(void)
280 {
281 HashKeys cur;
282 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
283 HashKeys prev;
284 HashKeys next;
285 #endif
286
287 ComputeKeys(mKeySequence, cur);
288 mMleKey = cur.mKeys.mMleKey;
289
290 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
291 ComputeKeys(mKeySequence - 1, prev);
292 ComputeKeys(mKeySequence + 1, next);
293
294 Get<Mac::SubMac>().SetMacKey(Mac::Frame::kKeyIdMode1, (mKeySequence & 0x7f) + 1, prev.mKeys.mMacKey,
295 cur.mKeys.mMacKey, next.mKeys.mMacKey);
296 #endif
297
298 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
299 ComputeTrelKey(mKeySequence, mTrelKey);
300 #endif
301 }
302
SetCurrentKeySequence(uint32_t aKeySequence)303 void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
304 {
305 VerifyOrExit(aKeySequence != mKeySequence, Get<Notifier>().SignalIfFirst(kEventThreadKeySeqCounterChanged));
306
307 if ((aKeySequence == (mKeySequence + 1)) && mKeyRotationTimer.IsRunning())
308 {
309 if (mKeySwitchGuardEnabled)
310 {
311 // Check if the guard timer has expired if key rotation is requested.
312 VerifyOrExit(mHoursSinceKeyRotation >= mKeySwitchGuardTime);
313 StartKeyRotationTimer();
314 }
315
316 mKeySwitchGuardEnabled = true;
317 }
318
319 mKeySequence = aKeySequence;
320 UpdateKeyMaterial();
321
322 mMacFrameCounters.Reset();
323 mMleFrameCounter = 0;
324
325 Get<Notifier>().Signal(kEventThreadKeySeqCounterChanged);
326
327 exit:
328 return;
329 }
330
GetTemporaryMleKey(uint32_t aKeySequence)331 const Mle::Key &KeyManager::GetTemporaryMleKey(uint32_t aKeySequence)
332 {
333 HashKeys hashKeys;
334
335 ComputeKeys(aKeySequence, hashKeys);
336 mTemporaryMleKey = hashKeys.mKeys.mMleKey;
337
338 return mTemporaryMleKey;
339 }
340
341 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
GetTemporaryTrelMacKey(uint32_t aKeySequence)342 const Mac::Key &KeyManager::GetTemporaryTrelMacKey(uint32_t aKeySequence)
343 {
344 ComputeTrelKey(aKeySequence, mTemporaryTrelKey);
345
346 return mTemporaryTrelKey;
347 }
348 #endif
349
SetAllMacFrameCounters(uint32_t aMacFrameCounter)350 void KeyManager::SetAllMacFrameCounters(uint32_t aMacFrameCounter)
351 {
352 mMacFrameCounters.SetAll(aMacFrameCounter);
353
354 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
355 Get<Mac::SubMac>().SetFrameCounter(aMacFrameCounter);
356 #endif
357 }
358
359 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
MacFrameCounterUpdated(uint32_t aMacFrameCounter)360 void KeyManager::MacFrameCounterUpdated(uint32_t aMacFrameCounter)
361 {
362 mMacFrameCounters.Set154(aMacFrameCounter);
363
364 if (mMacFrameCounters.Get154() >= mStoredMacFrameCounter)
365 {
366 IgnoreError(Get<Mle::MleRouter>().Store());
367 }
368 }
369 #else
MacFrameCounterUpdated(uint32_t)370 void KeyManager::MacFrameCounterUpdated(uint32_t)
371 {
372 }
373 #endif
374
375 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
IncrementTrelMacFrameCounter(void)376 void KeyManager::IncrementTrelMacFrameCounter(void)
377 {
378 mMacFrameCounters.IncrementTrel();
379
380 if (mMacFrameCounters.GetTrel() >= mStoredMacFrameCounter)
381 {
382 IgnoreError(Get<Mle::MleRouter>().Store());
383 }
384 }
385 #endif
386
IncrementMleFrameCounter(void)387 void KeyManager::IncrementMleFrameCounter(void)
388 {
389 mMleFrameCounter++;
390
391 if (mMleFrameCounter >= mStoredMleFrameCounter)
392 {
393 IgnoreError(Get<Mle::MleRouter>().Store());
394 }
395 }
396
SetKek(const Kek & aKek)397 void KeyManager::SetKek(const Kek &aKek)
398 {
399 mKek = aKek;
400 mKekFrameCounter = 0;
401 }
402
SetKek(const uint8_t * aKek)403 void KeyManager::SetKek(const uint8_t *aKek)
404 {
405 memcpy(mKek.m8, aKek, sizeof(mKek));
406 mKekFrameCounter = 0;
407 }
408
SetSecurityPolicy(const SecurityPolicy & aSecurityPolicy)409 void KeyManager::SetSecurityPolicy(const SecurityPolicy &aSecurityPolicy)
410 {
411 OT_ASSERT(aSecurityPolicy.mRotationTime >= SecurityPolicy::kMinKeyRotationTime);
412
413 IgnoreError(Get<Notifier>().Update(mSecurityPolicy, aSecurityPolicy, kEventSecurityPolicyChanged));
414 }
415
StartKeyRotationTimer(void)416 void KeyManager::StartKeyRotationTimer(void)
417 {
418 mHoursSinceKeyRotation = 0;
419 mKeyRotationTimer.Start(kOneHourIntervalInMsec);
420 }
421
HandleKeyRotationTimer(Timer & aTimer)422 void KeyManager::HandleKeyRotationTimer(Timer &aTimer)
423 {
424 aTimer.Get<KeyManager>().HandleKeyRotationTimer();
425 }
426
HandleKeyRotationTimer(void)427 void KeyManager::HandleKeyRotationTimer(void)
428 {
429 mHoursSinceKeyRotation++;
430
431 // Order of operations below is important. We should restart the timer (from
432 // last fire time for one hour interval) before potentially calling
433 // `SetCurrentKeySequence()`. `SetCurrentKeySequence()` uses the fact that
434 // timer is running to decide to check for the guard time and to reset the
435 // rotation timer (and the `mHoursSinceKeyRotation`) if it updates the key
436 // sequence.
437
438 mKeyRotationTimer.StartAt(mKeyRotationTimer.GetFireTime(), kOneHourIntervalInMsec);
439
440 if (mHoursSinceKeyRotation >= mSecurityPolicy.mRotationTime)
441 {
442 SetCurrentKeySequence(mKeySequence + 1);
443 }
444 }
445
446 } // namespace ot
447