• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016-2017, 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 common methods for manipulating MeshCoP Datasets.
32  *
33  */
34 
35 #include "dataset_local.hpp"
36 
37 #include <stdio.h>
38 
39 #include "common/code_utils.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 #include "common/settings.hpp"
43 #include "crypto/storage.hpp"
44 #include "instance/instance.hpp"
45 #include "meshcop/dataset.hpp"
46 #include "meshcop/meshcop_tlvs.hpp"
47 #include "thread/mle_tlvs.hpp"
48 
49 namespace ot {
50 namespace MeshCoP {
51 
52 RegisterLogModule("DatasetLocal");
53 
DatasetLocal(Instance & aInstance,Dataset::Type aType)54 DatasetLocal::DatasetLocal(Instance &aInstance, Dataset::Type aType)
55     : InstanceLocator(aInstance)
56     , mUpdateTime(0)
57     , mType(aType)
58     , mTimestampPresent(false)
59     , mSaved(false)
60 {
61     mTimestamp.Clear();
62 }
63 
Clear(void)64 void DatasetLocal::Clear(void)
65 {
66 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
67     DestroySecurelyStoredKeys();
68 #endif
69     IgnoreError(Get<Settings>().DeleteOperationalDataset(mType));
70     mTimestamp.Clear();
71     mTimestampPresent = false;
72     mSaved            = false;
73 }
74 
Restore(Dataset & aDataset)75 Error DatasetLocal::Restore(Dataset &aDataset)
76 {
77     Error error;
78 
79     mTimestampPresent = false;
80 
81     error = Read(aDataset);
82     SuccessOrExit(error);
83 
84     mSaved            = true;
85     mTimestampPresent = (aDataset.GetTimestamp(mType, mTimestamp) == kErrorNone);
86 
87 exit:
88     return error;
89 }
90 
Read(Dataset & aDataset) const91 Error DatasetLocal::Read(Dataset &aDataset) const
92 {
93     Error error;
94 
95     error = Get<Settings>().ReadOperationalDataset(mType, aDataset);
96     VerifyOrExit(error == kErrorNone, aDataset.mLength = 0);
97 
98 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
99     EmplaceSecurelyStoredKeys(aDataset);
100 #endif
101 
102     if (mType == Dataset::kActive)
103     {
104         aDataset.RemoveTlv(Tlv::kPendingTimestamp);
105         aDataset.RemoveTlv(Tlv::kDelayTimer);
106     }
107     else
108     {
109         uint32_t elapsed;
110         uint32_t delayTimer;
111         Tlv     *tlv = aDataset.FindTlv(Tlv::kDelayTimer);
112 
113         VerifyOrExit(tlv != nullptr);
114 
115         elapsed    = TimerMilli::GetNow() - mUpdateTime;
116         delayTimer = tlv->ReadValueAs<DelayTimerTlv>();
117 
118         if (delayTimer > elapsed)
119         {
120             delayTimer -= elapsed;
121         }
122         else
123         {
124             delayTimer = 0;
125         }
126 
127         tlv->WriteValueAs<DelayTimerTlv>(delayTimer);
128     }
129 
130     aDataset.mUpdateTime = TimerMilli::GetNow();
131 
132 exit:
133     return error;
134 }
135 
Read(Dataset::Info & aDatasetInfo) const136 Error DatasetLocal::Read(Dataset::Info &aDatasetInfo) const
137 {
138     Dataset dataset;
139     Error   error;
140 
141     aDatasetInfo.Clear();
142 
143     SuccessOrExit(error = Read(dataset));
144     dataset.ConvertTo(aDatasetInfo);
145 
146 exit:
147     return error;
148 }
149 
Read(Dataset::Tlvs & aDatasetTlvs) const150 Error DatasetLocal::Read(Dataset::Tlvs &aDatasetTlvs) const
151 {
152     Dataset dataset;
153     Error   error;
154 
155     ClearAllBytes(aDatasetTlvs);
156 
157     SuccessOrExit(error = Read(dataset));
158     dataset.ConvertTo(aDatasetTlvs);
159 
160 exit:
161     return error;
162 }
163 
Save(const Dataset::Info & aDatasetInfo)164 Error DatasetLocal::Save(const Dataset::Info &aDatasetInfo)
165 {
166     Error   error;
167     Dataset dataset;
168 
169     SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
170     SuccessOrExit(error = Save(dataset));
171 
172 exit:
173     return error;
174 }
175 
Save(const Dataset::Tlvs & aDatasetTlvs)176 Error DatasetLocal::Save(const Dataset::Tlvs &aDatasetTlvs)
177 {
178     Dataset dataset;
179 
180     dataset.SetFrom(aDatasetTlvs);
181 
182     return Save(dataset);
183 }
184 
Save(const Dataset & aDataset)185 Error DatasetLocal::Save(const Dataset &aDataset)
186 {
187     Error error = kErrorNone;
188 
189 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
190     DestroySecurelyStoredKeys();
191 #endif
192 
193     if (aDataset.GetSize() == 0)
194     {
195         // do not propagate error back
196         IgnoreError(Get<Settings>().DeleteOperationalDataset(mType));
197         mSaved = false;
198         LogInfo("%s dataset deleted", Dataset::TypeToString(mType));
199     }
200     else
201     {
202 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
203         // Store the network key and PSKC in the secure storage instead of settings.
204         Dataset dataset;
205 
206         dataset.Set(GetType(), aDataset);
207         MoveKeysToSecureStorage(dataset);
208         SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, dataset));
209 #else
210         SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, aDataset));
211 #endif
212 
213         mSaved = true;
214         LogInfo("%s dataset set", Dataset::TypeToString(mType));
215     }
216 
217     mTimestampPresent = (aDataset.GetTimestamp(mType, mTimestamp) == kErrorNone);
218     mUpdateTime       = TimerMilli::GetNow();
219 
220 exit:
221     return error;
222 }
223 
224 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
225 
226 const DatasetLocal::SecurelyStoredTlv DatasetLocal::kSecurelyStoredTlvs[] = {
227     {
228         Tlv::kNetworkKey,
229         Crypto::Storage::kActiveDatasetNetworkKeyRef,
230         Crypto::Storage::kPendingDatasetNetworkKeyRef,
231     },
232     {
233         Tlv::kPskc,
234         Crypto::Storage::kActiveDatasetPskcRef,
235         Crypto::Storage::kPendingDatasetPskcRef,
236     },
237 };
238 
DestroySecurelyStoredKeys(void) const239 void DatasetLocal::DestroySecurelyStoredKeys(void) const
240 {
241     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
242     {
243         Crypto::Storage::DestroyKey(entry.GetKeyRef(mType));
244     }
245 }
246 
MoveKeysToSecureStorage(Dataset & aDataset) const247 void DatasetLocal::MoveKeysToSecureStorage(Dataset &aDataset) const
248 {
249     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
250     {
251         aDataset.SaveTlvInSecureStorageAndClearValue(entry.mTlvType, entry.GetKeyRef(mType));
252     }
253 }
254 
EmplaceSecurelyStoredKeys(Dataset & aDataset) const255 void DatasetLocal::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
256 {
257     bool moveKeys = false;
258 
259     // If reading any of the TLVs fails, it indicates they are not yet
260     // stored in secure storage and are still contained in the `Dataset`
261     // read from `Settings`. In this case, we move the keys to secure
262     // storage and then clear them from 'Settings'.
263 
264     for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs)
265     {
266         if (aDataset.ReadTlvFromSecureStorage(entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone)
267         {
268             moveKeys = true;
269         }
270     }
271 
272     if (moveKeys)
273     {
274         Dataset dataset;
275 
276         dataset.Set(GetType(), aDataset);
277         MoveKeysToSecureStorage(dataset);
278         SuccessOrAssert(Get<Settings>().SaveOperationalDataset(mType, dataset));
279     }
280 }
281 
282 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
283 
284 } // namespace MeshCoP
285 } // namespace ot
286