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