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