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/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/settings.hpp"
44 #include "crypto/storage.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 DelayTimerTlv *delayTimer;
94 uint32_t elapsed;
95 Error error;
96
97 error = Get<Settings>().ReadOperationalDataset(mType, aDataset);
98 VerifyOrExit(error == kErrorNone, aDataset.mLength = 0);
99
100 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
101 EmplaceSecurelyStoredKeys(aDataset);
102 #endif
103
104 if (mType == Dataset::kActive)
105 {
106 aDataset.RemoveTlv(Tlv::kPendingTimestamp);
107 aDataset.RemoveTlv(Tlv::kDelayTimer);
108 }
109 else
110 {
111 delayTimer = aDataset.GetTlv<DelayTimerTlv>();
112 VerifyOrExit(delayTimer);
113
114 elapsed = TimerMilli::GetNow() - mUpdateTime;
115
116 if (delayTimer->GetDelayTimer() > elapsed)
117 {
118 delayTimer->SetDelayTimer(delayTimer->GetDelayTimer() - elapsed);
119 }
120 else
121 {
122 delayTimer->SetDelayTimer(0);
123 }
124 }
125
126 aDataset.mUpdateTime = TimerMilli::GetNow();
127
128 exit:
129 return error;
130 }
131
Read(Dataset::Info & aDatasetInfo) const132 Error DatasetLocal::Read(Dataset::Info &aDatasetInfo) const
133 {
134 Dataset dataset;
135 Error error;
136
137 aDatasetInfo.Clear();
138
139 SuccessOrExit(error = Read(dataset));
140 dataset.ConvertTo(aDatasetInfo);
141
142 exit:
143 return error;
144 }
145
Read(otOperationalDatasetTlvs & aDataset) const146 Error DatasetLocal::Read(otOperationalDatasetTlvs &aDataset) const
147 {
148 Dataset dataset;
149 Error error;
150
151 memset(&aDataset, 0, sizeof(aDataset));
152
153 SuccessOrExit(error = Read(dataset));
154 dataset.ConvertTo(aDataset);
155
156 exit:
157 return error;
158 }
159
Save(const Dataset::Info & aDatasetInfo)160 Error DatasetLocal::Save(const Dataset::Info &aDatasetInfo)
161 {
162 Error error;
163 Dataset dataset;
164
165 SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
166 SuccessOrExit(error = Save(dataset));
167
168 exit:
169 return error;
170 }
171
Save(const otOperationalDatasetTlvs & aDataset)172 Error DatasetLocal::Save(const otOperationalDatasetTlvs &aDataset)
173 {
174 Dataset dataset;
175
176 dataset.SetFrom(aDataset);
177
178 return Save(dataset);
179 }
180
Save(const Dataset & aDataset)181 Error DatasetLocal::Save(const Dataset &aDataset)
182 {
183 Error error = kErrorNone;
184
185 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
186 DestroySecurelyStoredKeys();
187 #endif
188
189 if (aDataset.GetSize() == 0)
190 {
191 // do not propagate error back
192 IgnoreError(Get<Settings>().DeleteOperationalDataset(mType));
193 mSaved = false;
194 LogInfo("%s dataset deleted", Dataset::TypeToString(mType));
195 }
196 else
197 {
198 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
199 // Store the network key and PSKC in the secure storage instead of settings.
200 Dataset dataset;
201
202 dataset.Set(GetType(), aDataset);
203 MoveKeysToSecureStorage(dataset);
204 SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, dataset));
205 #else
206 SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, aDataset));
207 #endif
208
209 mSaved = true;
210 LogInfo("%s dataset set", Dataset::TypeToString(mType));
211 }
212
213 mTimestampPresent = (aDataset.GetTimestamp(mType, mTimestamp) == kErrorNone);
214 mUpdateTime = TimerMilli::GetNow();
215
216 exit:
217 return error;
218 }
219
220 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
DestroySecurelyStoredKeys(void) const221 void DatasetLocal::DestroySecurelyStoredKeys(void) const
222 {
223 using namespace Crypto::Storage;
224
225 KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
226 KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
227
228 // Destroy securely stored keys associated with the given operational dataset type.
229 DestroyKey(networkKeyRef);
230 DestroyKey(pskcRef);
231 }
232
MoveKeysToSecureStorage(Dataset & aDataset) const233 void DatasetLocal::MoveKeysToSecureStorage(Dataset &aDataset) const
234 {
235 using namespace Crypto::Storage;
236
237 KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
238 KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
239 NetworkKeyTlv *networkKeyTlv = aDataset.GetTlv<NetworkKeyTlv>();
240 PskcTlv *pskcTlv = aDataset.GetTlv<PskcTlv>();
241
242 if (networkKeyTlv != nullptr)
243 {
244 // If the dataset contains a network key, put it in the secure storage
245 // and zero the corresponding TLV element.
246 NetworkKey networkKey;
247 SuccessOrAssert(ImportKey(networkKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent,
248 networkKeyTlv->GetNetworkKey().m8, NetworkKey::kSize));
249 networkKey.Clear();
250 networkKeyTlv->SetNetworkKey(networkKey);
251 }
252
253 if (pskcTlv != nullptr)
254 {
255 // If the dataset contains a PSKC, put it in the secure storage and zero
256 // the corresponding TLV element.
257 Pskc pskc;
258 SuccessOrAssert(ImportKey(pskcRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent,
259 pskcTlv->GetPskc().m8, Pskc::kSize));
260 pskc.Clear();
261 pskcTlv->SetPskc(pskc);
262 }
263 }
264
EmplaceSecurelyStoredKeys(Dataset & aDataset) const265 void DatasetLocal::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
266 {
267 using namespace Crypto::Storage;
268
269 KeyRef networkKeyRef = IsActive() ? kActiveDatasetNetworkKeyRef : kPendingDatasetNetworkKeyRef;
270 KeyRef pskcRef = IsActive() ? kActiveDatasetPskcRef : kPendingDatasetPskcRef;
271 NetworkKeyTlv *networkKeyTlv = aDataset.GetTlv<NetworkKeyTlv>();
272 PskcTlv *pskcTlv = aDataset.GetTlv<PskcTlv>();
273 bool moveKeys = false;
274 size_t keyLen;
275 Error error;
276
277 if (networkKeyTlv != nullptr)
278 {
279 // If the dataset contains a network key, its real value must have been moved to
280 // the secure storage upon saving the dataset, so restore it back now.
281 NetworkKey networkKey;
282 error = ExportKey(networkKeyRef, networkKey.m8, NetworkKey::kSize, keyLen);
283
284 if (error != kErrorNone)
285 {
286 // If ExportKey fails, key is not in secure storage and is stored in settings
287 moveKeys = true;
288 }
289 else
290 {
291 OT_ASSERT(keyLen == NetworkKey::kSize);
292 networkKeyTlv->SetNetworkKey(networkKey);
293 }
294 }
295
296 if (pskcTlv != nullptr)
297 {
298 // If the dataset contains a PSKC, its real value must have been moved to
299 // the secure storage upon saving the dataset, so restore it back now.
300 Pskc pskc;
301 error = ExportKey(pskcRef, pskc.m8, Pskc::kSize, keyLen);
302
303 if (error != kErrorNone)
304 {
305 // If ExportKey fails, key is not in secure storage and is stored in settings
306 moveKeys = true;
307 }
308 else
309 {
310 OT_ASSERT(keyLen == Pskc::kSize);
311 pskcTlv->SetPskc(pskc);
312 }
313 }
314
315 if (moveKeys)
316 {
317 // Clear the networkkey and Pskc stored in the settings and move them to secure storage.
318 // Store the network key and PSKC in the secure storage instead of settings.
319 Dataset dataset;
320
321 dataset.Set(GetType(), aDataset);
322 MoveKeysToSecureStorage(dataset);
323 SuccessOrAssert(error = Get<Settings>().SaveOperationalDataset(mType, dataset));
324 }
325 }
326 #endif
327
328 } // namespace MeshCoP
329 } // namespace ot
330