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