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 common methods for manipulating MeshCoP Datasets.
32  *
33  */
34 
35 #include "dataset.hpp"
36 
37 #include <stdio.h>
38 
39 #include "common/code_utils.hpp"
40 #include "common/encoding.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "instance/instance.hpp"
44 #include "mac/mac_types.hpp"
45 #include "meshcop/meshcop_tlvs.hpp"
46 #include "meshcop/timestamp.hpp"
47 #include "thread/mle_tlvs.hpp"
48 
49 namespace ot {
50 namespace MeshCoP {
51 
52 RegisterLogModule("Dataset");
53 
GenerateRandom(Instance & aInstance)54 Error Dataset::Info::GenerateRandom(Instance &aInstance)
55 {
56     Error            error;
57     Mac::ChannelMask supportedChannels = aInstance.Get<Mac::Mac>().GetSupportedChannelMask();
58     Mac::ChannelMask preferredChannels(aInstance.Get<Radio>().GetPreferredChannelMask());
59 
60     // If the preferred channel mask is not empty, select a random
61     // channel from it, otherwise choose one from the supported
62     // channel mask.
63 
64     preferredChannels.Intersect(supportedChannels);
65 
66     if (preferredChannels.IsEmpty())
67     {
68         preferredChannels = supportedChannels;
69     }
70 
71     Clear();
72 
73     mActiveTimestamp.mSeconds       = 1;
74     mActiveTimestamp.mTicks         = 0;
75     mActiveTimestamp.mAuthoritative = false;
76     mChannel                        = preferredChannels.ChooseRandomChannel();
77     mChannelMask                    = supportedChannels.GetMask();
78     mPanId                          = Mac::GenerateRandomPanId();
79     AsCoreType(&mSecurityPolicy).SetToDefault();
80 
81     SuccessOrExit(error = AsCoreType(&mNetworkKey).GenerateRandom());
82     SuccessOrExit(error = AsCoreType(&mPskc).GenerateRandom());
83     SuccessOrExit(error = Random::Crypto::Fill(mExtendedPanId));
84     SuccessOrExit(error = AsCoreType(&mMeshLocalPrefix).GenerateRandomUla());
85 
86     snprintf(mNetworkName.m8, sizeof(mNetworkName), "%s-%04x", NetworkName::kNetworkNameInit, mPanId);
87 
88     mComponents.mIsActiveTimestampPresent = true;
89     mComponents.mIsNetworkKeyPresent      = true;
90     mComponents.mIsNetworkNamePresent     = true;
91     mComponents.mIsExtendedPanIdPresent   = true;
92     mComponents.mIsMeshLocalPrefixPresent = true;
93     mComponents.mIsPanIdPresent           = true;
94     mComponents.mIsChannelPresent         = true;
95     mComponents.mIsPskcPresent            = true;
96     mComponents.mIsSecurityPolicyPresent  = true;
97     mComponents.mIsChannelMaskPresent     = true;
98 
99 exit:
100     return error;
101 }
102 
IsSubsetOf(const Info & aOther) const103 bool Dataset::Info::IsSubsetOf(const Info &aOther) const
104 {
105     bool isSubset = false;
106 
107     if (IsNetworkKeyPresent())
108     {
109         VerifyOrExit(aOther.IsNetworkKeyPresent() && GetNetworkKey() == aOther.GetNetworkKey());
110     }
111 
112     if (IsNetworkNamePresent())
113     {
114         VerifyOrExit(aOther.IsNetworkNamePresent() && GetNetworkName() == aOther.GetNetworkName());
115     }
116 
117     if (IsExtendedPanIdPresent())
118     {
119         VerifyOrExit(aOther.IsExtendedPanIdPresent() && GetExtendedPanId() == aOther.GetExtendedPanId());
120     }
121 
122     if (IsMeshLocalPrefixPresent())
123     {
124         VerifyOrExit(aOther.IsMeshLocalPrefixPresent() && GetMeshLocalPrefix() == aOther.GetMeshLocalPrefix());
125     }
126 
127     if (IsPanIdPresent())
128     {
129         VerifyOrExit(aOther.IsPanIdPresent() && GetPanId() == aOther.GetPanId());
130     }
131 
132     if (IsChannelPresent())
133     {
134         VerifyOrExit(aOther.IsChannelPresent() && GetChannel() == aOther.GetChannel());
135     }
136 
137     if (IsPskcPresent())
138     {
139         VerifyOrExit(aOther.IsPskcPresent() && GetPskc() == aOther.GetPskc());
140     }
141 
142     if (IsSecurityPolicyPresent())
143     {
144         VerifyOrExit(aOther.IsSecurityPolicyPresent() && GetSecurityPolicy() == aOther.GetSecurityPolicy());
145     }
146 
147     if (IsChannelMaskPresent())
148     {
149         VerifyOrExit(aOther.IsChannelMaskPresent() && GetChannelMask() == aOther.GetChannelMask());
150     }
151 
152     isSubset = true;
153 
154 exit:
155     return isSubset;
156 }
157 
Dataset(void)158 Dataset::Dataset(void)
159     : mUpdateTime(0)
160     , mLength(0)
161 {
162     memset(mTlvs, 0, sizeof(mTlvs));
163 }
164 
Clear(void)165 void Dataset::Clear(void) { mLength = 0; }
166 
IsValid(void) const167 bool Dataset::IsValid(void) const
168 {
169     bool       rval = true;
170     const Tlv *end  = GetTlvsEnd();
171 
172     for (const Tlv *cur = GetTlvsStart(); cur < end; cur = cur->GetNext())
173     {
174         VerifyOrExit(!cur->IsExtended() && (cur + 1) <= end && cur->GetNext() <= end && Tlv::IsValid(*cur),
175                      rval = false);
176     }
177 
178 exit:
179     return rval;
180 }
181 
FindTlv(Tlv::Type aType) const182 const Tlv *Dataset::FindTlv(Tlv::Type aType) const { return As<Tlv>(Tlv::FindTlv(mTlvs, mLength, aType)); }
183 
ConvertTo(Info & aDatasetInfo) const184 void Dataset::ConvertTo(Info &aDatasetInfo) const
185 {
186     aDatasetInfo.Clear();
187 
188     for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
189     {
190         switch (cur->GetType())
191         {
192         case Tlv::kActiveTimestamp:
193             aDatasetInfo.SetActiveTimestamp(cur->ReadValueAs<ActiveTimestampTlv>());
194             break;
195 
196         case Tlv::kChannel:
197             aDatasetInfo.SetChannel(cur->ReadValueAs<ChannelTlv>().GetChannel());
198             break;
199 
200         case Tlv::kChannelMask:
201         {
202             uint32_t mask;
203 
204             if (As<ChannelMaskTlv>(cur)->ReadChannelMask(mask) == kErrorNone)
205             {
206                 aDatasetInfo.SetChannelMask(mask);
207             }
208 
209             break;
210         }
211 
212         case Tlv::kDelayTimer:
213             aDatasetInfo.SetDelay(cur->ReadValueAs<DelayTimerTlv>());
214             break;
215 
216         case Tlv::kExtendedPanId:
217             aDatasetInfo.SetExtendedPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
218             break;
219 
220         case Tlv::kMeshLocalPrefix:
221             aDatasetInfo.SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
222             break;
223 
224         case Tlv::kNetworkKey:
225             aDatasetInfo.SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
226             break;
227 
228         case Tlv::kNetworkName:
229             aDatasetInfo.SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName());
230             break;
231 
232         case Tlv::kPanId:
233             aDatasetInfo.SetPanId(cur->ReadValueAs<PanIdTlv>());
234             break;
235 
236         case Tlv::kPendingTimestamp:
237             aDatasetInfo.SetPendingTimestamp(cur->ReadValueAs<PendingTimestampTlv>());
238             break;
239 
240         case Tlv::kPskc:
241             aDatasetInfo.SetPskc(cur->ReadValueAs<PskcTlv>());
242             break;
243 
244         case Tlv::kSecurityPolicy:
245             aDatasetInfo.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
246             break;
247 
248         default:
249             break;
250         }
251     }
252 }
253 
ConvertTo(otOperationalDatasetTlvs & aDataset) const254 void Dataset::ConvertTo(otOperationalDatasetTlvs &aDataset) const
255 {
256     memcpy(aDataset.mTlvs, mTlvs, mLength);
257     aDataset.mLength = static_cast<uint8_t>(mLength);
258 }
259 
Set(Type aType,const Dataset & aDataset)260 void Dataset::Set(Type aType, const Dataset &aDataset)
261 {
262     memcpy(mTlvs, aDataset.mTlvs, aDataset.mLength);
263     mLength = aDataset.mLength;
264 
265     if (aType == kActive)
266     {
267         RemoveTlv(Tlv::kPendingTimestamp);
268         RemoveTlv(Tlv::kDelayTimer);
269     }
270 
271     mUpdateTime = aDataset.GetUpdateTime();
272 }
273 
SetFrom(const otOperationalDatasetTlvs & aDataset)274 void Dataset::SetFrom(const otOperationalDatasetTlvs &aDataset)
275 {
276     mLength = aDataset.mLength;
277     memcpy(mTlvs, aDataset.mTlvs, mLength);
278 }
279 
SetFrom(const Info & aDatasetInfo)280 Error Dataset::SetFrom(const Info &aDatasetInfo)
281 {
282     Error error = kErrorNone;
283 
284     if (aDatasetInfo.IsActiveTimestampPresent())
285     {
286         Timestamp activeTimestamp;
287 
288         aDatasetInfo.GetActiveTimestamp(activeTimestamp);
289         IgnoreError(Write<ActiveTimestampTlv>(activeTimestamp));
290     }
291 
292     if (aDatasetInfo.IsPendingTimestampPresent())
293     {
294         Timestamp pendingTimestamp;
295 
296         aDatasetInfo.GetPendingTimestamp(pendingTimestamp);
297         IgnoreError(Write<PendingTimestampTlv>(pendingTimestamp));
298     }
299 
300     if (aDatasetInfo.IsDelayPresent())
301     {
302         IgnoreError(Write<DelayTimerTlv>(aDatasetInfo.GetDelay()));
303     }
304 
305     if (aDatasetInfo.IsChannelPresent())
306     {
307         ChannelTlvValue channelValue;
308 
309         channelValue.SetChannelAndPage(aDatasetInfo.GetChannel());
310         IgnoreError(Write<ChannelTlv>(channelValue));
311     }
312 
313     if (aDatasetInfo.IsChannelMaskPresent())
314     {
315         ChannelMaskTlv::Value value;
316 
317         ChannelMaskTlv::PrepareValue(value, aDatasetInfo.GetChannelMask());
318         IgnoreError(WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
319     }
320 
321     if (aDatasetInfo.IsExtendedPanIdPresent())
322     {
323         IgnoreError(Write<ExtendedPanIdTlv>(aDatasetInfo.GetExtendedPanId()));
324     }
325 
326     if (aDatasetInfo.IsMeshLocalPrefixPresent())
327     {
328         IgnoreError(Write<MeshLocalPrefixTlv>(aDatasetInfo.GetMeshLocalPrefix()));
329     }
330 
331     if (aDatasetInfo.IsNetworkKeyPresent())
332     {
333         IgnoreError(Write<NetworkKeyTlv>(aDatasetInfo.GetNetworkKey()));
334     }
335 
336     if (aDatasetInfo.IsNetworkNamePresent())
337     {
338         NameData nameData = aDatasetInfo.GetNetworkName().GetAsData();
339 
340         IgnoreError(WriteTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
341     }
342 
343     if (aDatasetInfo.IsPanIdPresent())
344     {
345         IgnoreError(Write<PanIdTlv>(aDatasetInfo.GetPanId()));
346     }
347 
348     if (aDatasetInfo.IsPskcPresent())
349     {
350         IgnoreError(Write<PskcTlv>(aDatasetInfo.GetPskc()));
351     }
352 
353     if (aDatasetInfo.IsSecurityPolicyPresent())
354     {
355         SecurityPolicyTlv tlv;
356 
357         tlv.Init();
358         tlv.SetSecurityPolicy(aDatasetInfo.GetSecurityPolicy());
359         IgnoreError(WriteTlv(tlv));
360     }
361 
362     mUpdateTime = TimerMilli::GetNow();
363 
364     return error;
365 }
366 
GetTimestamp(Type aType,Timestamp & aTimestamp) const367 Error Dataset::GetTimestamp(Type aType, Timestamp &aTimestamp) const
368 {
369     Error      error = kErrorNone;
370     const Tlv *tlv;
371 
372     if (aType == kActive)
373     {
374         tlv = FindTlv(Tlv::kActiveTimestamp);
375         VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
376         aTimestamp = tlv->ReadValueAs<ActiveTimestampTlv>();
377     }
378     else
379     {
380         tlv = FindTlv(Tlv::kPendingTimestamp);
381         VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
382         aTimestamp = tlv->ReadValueAs<PendingTimestampTlv>();
383     }
384 
385 exit:
386     return error;
387 }
388 
SetTimestamp(Type aType,const Timestamp & aTimestamp)389 void Dataset::SetTimestamp(Type aType, const Timestamp &aTimestamp)
390 {
391     if (aType == kActive)
392     {
393         IgnoreError(Write<ActiveTimestampTlv>(aTimestamp));
394     }
395     else
396     {
397         IgnoreError(Write<PendingTimestampTlv>(aTimestamp));
398     }
399 }
400 
WriteTlv(Tlv::Type aType,const void * aValue,uint8_t aLength)401 Error Dataset::WriteTlv(Tlv::Type aType, const void *aValue, uint8_t aLength)
402 {
403     Error    error          = kErrorNone;
404     uint16_t bytesAvailable = sizeof(mTlvs) - mLength;
405     Tlv     *oldTlv         = FindTlv(aType);
406     Tlv     *newTlv;
407 
408     if (oldTlv != nullptr)
409     {
410         bytesAvailable += sizeof(Tlv) + oldTlv->GetLength();
411     }
412 
413     VerifyOrExit(sizeof(Tlv) + aLength <= bytesAvailable, error = kErrorNoBufs);
414 
415     RemoveTlv(oldTlv);
416 
417     newTlv = GetTlvsEnd();
418     mLength += sizeof(Tlv) + aLength;
419 
420     newTlv->SetType(aType);
421     newTlv->SetLength(aLength);
422     memcpy(newTlv->GetValue(), aValue, aLength);
423 
424     mUpdateTime = TimerMilli::GetNow();
425 
426 exit:
427     return error;
428 }
429 
WriteTlv(const Tlv & aTlv)430 Error Dataset::WriteTlv(const Tlv &aTlv) { return WriteTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength()); }
431 
ReadFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)432 Error Dataset::ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
433 {
434     Error error = kErrorParse;
435 
436     VerifyOrExit(aLength <= kMaxSize);
437 
438     SuccessOrExit(aMessage.Read(aOffset, mTlvs, aLength));
439     mLength = aLength;
440 
441     VerifyOrExit(IsValid(), error = kErrorParse);
442 
443     mUpdateTime = TimerMilli::GetNow();
444     error       = kErrorNone;
445 
446 exit:
447     return error;
448 }
449 
RemoveTlv(Tlv::Type aType)450 void Dataset::RemoveTlv(Tlv::Type aType) { RemoveTlv(FindTlv(aType)); }
451 
AppendMleDatasetTlv(Type aType,Message & aMessage) const452 Error Dataset::AppendMleDatasetTlv(Type aType, Message &aMessage) const
453 {
454     Error          error = kErrorNone;
455     Mle::Tlv       tlv;
456     Mle::Tlv::Type type;
457 
458     VerifyOrExit(mLength > 0);
459 
460     type = (aType == kActive ? Mle::Tlv::kActiveDataset : Mle::Tlv::kPendingDataset);
461 
462     tlv.SetType(type);
463     tlv.SetLength(static_cast<uint8_t>(mLength) - sizeof(Tlv) - sizeof(Timestamp));
464     SuccessOrExit(error = aMessage.Append(tlv));
465 
466     for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
467     {
468         if (((aType == kActive) && (cur->GetType() == Tlv::kActiveTimestamp)) ||
469             ((aType == kPending) && (cur->GetType() == Tlv::kPendingTimestamp)))
470         {
471             ; // skip Active or Pending Timestamp TLV
472         }
473         else if (cur->GetType() == Tlv::kDelayTimer)
474         {
475             uint32_t elapsed    = TimerMilli::GetNow() - mUpdateTime;
476             uint32_t delayTimer = cur->ReadValueAs<DelayTimerTlv>();
477 
478             if (delayTimer > elapsed)
479             {
480                 delayTimer -= elapsed;
481             }
482             else
483             {
484                 delayTimer = 0;
485             }
486 
487             SuccessOrExit(error = Tlv::Append<DelayTimerTlv>(aMessage, delayTimer));
488         }
489         else
490         {
491             SuccessOrExit(error = cur->AppendTo(aMessage));
492         }
493     }
494 
495 exit:
496     return error;
497 }
498 
RemoveTlv(Tlv * aTlv)499 void Dataset::RemoveTlv(Tlv *aTlv)
500 {
501     if (aTlv != nullptr)
502     {
503         uint8_t *start  = reinterpret_cast<uint8_t *>(aTlv);
504         uint16_t length = sizeof(Tlv) + aTlv->GetLength();
505 
506         memmove(start, start + length, mLength - (static_cast<uint8_t>(start - mTlvs) + length));
507         mLength -= length;
508     }
509 }
510 
ApplyConfiguration(Instance & aInstance,bool * aIsNetworkKeyUpdated) const511 Error Dataset::ApplyConfiguration(Instance &aInstance, bool *aIsNetworkKeyUpdated) const
512 {
513     Mac::Mac   &mac        = aInstance.Get<Mac::Mac>();
514     KeyManager &keyManager = aInstance.Get<KeyManager>();
515     Error       error      = kErrorNone;
516 
517     VerifyOrExit(IsValid(), error = kErrorParse);
518 
519     if (aIsNetworkKeyUpdated)
520     {
521         *aIsNetworkKeyUpdated = false;
522     }
523 
524     for (const Tlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
525     {
526         switch (cur->GetType())
527         {
528         case Tlv::kChannel:
529         {
530             uint8_t channel = static_cast<uint8_t>(cur->ReadValueAs<ChannelTlv>().GetChannel());
531 
532             error = mac.SetPanChannel(channel);
533 
534             if (error != kErrorNone)
535             {
536                 LogWarn("ApplyConfiguration() Failed to set channel to %d (%s)", channel, ErrorToString(error));
537                 ExitNow();
538             }
539 
540             break;
541         }
542 
543         case Tlv::kPanId:
544             mac.SetPanId(cur->ReadValueAs<PanIdTlv>());
545             break;
546 
547         case Tlv::kExtendedPanId:
548             aInstance.Get<ExtendedPanIdManager>().SetExtPanId(cur->ReadValueAs<ExtendedPanIdTlv>());
549             break;
550 
551         case Tlv::kNetworkName:
552             IgnoreError(aInstance.Get<NetworkNameManager>().SetNetworkName(As<NetworkNameTlv>(cur)->GetNetworkName()));
553             break;
554 
555         case Tlv::kNetworkKey:
556         {
557             NetworkKey networkKey;
558 
559             keyManager.GetNetworkKey(networkKey);
560 
561             if (aIsNetworkKeyUpdated && (cur->ReadValueAs<NetworkKeyTlv>() != networkKey))
562             {
563                 *aIsNetworkKeyUpdated = true;
564             }
565 
566             keyManager.SetNetworkKey(cur->ReadValueAs<NetworkKeyTlv>());
567             break;
568         }
569 
570 #if OPENTHREAD_FTD
571 
572         case Tlv::kPskc:
573             keyManager.SetPskc(cur->ReadValueAs<PskcTlv>());
574             break;
575 
576 #endif
577 
578         case Tlv::kMeshLocalPrefix:
579             aInstance.Get<Mle::MleRouter>().SetMeshLocalPrefix(cur->ReadValueAs<MeshLocalPrefixTlv>());
580             break;
581 
582         case Tlv::kSecurityPolicy:
583             keyManager.SetSecurityPolicy(As<SecurityPolicyTlv>(cur)->GetSecurityPolicy());
584             break;
585 
586         default:
587             break;
588         }
589     }
590 
591 exit:
592     return error;
593 }
594 
ConvertToActive(void)595 void Dataset::ConvertToActive(void)
596 {
597     RemoveTlv(Tlv::kPendingTimestamp);
598     RemoveTlv(Tlv::kDelayTimer);
599 }
600 
TypeToString(Type aType)601 const char *Dataset::TypeToString(Type aType) { return (aType == kActive) ? "Active" : "Pending"; }
602 
603 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
604 
SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType,Crypto::Storage::KeyRef aKeyRef)605 void Dataset::SaveTlvInSecureStorageAndClearValue(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef)
606 {
607     using namespace ot::Crypto::Storage;
608 
609     Tlv *tlv = FindTlv(aTlvType);
610 
611     VerifyOrExit(tlv != nullptr);
612     VerifyOrExit(tlv->GetLength() > 0);
613 
614     SuccessOrAssert(ImportKey(aKeyRef, kKeyTypeRaw, kKeyAlgorithmVendor, kUsageExport, kTypePersistent, tlv->GetValue(),
615                               tlv->GetLength()));
616 
617     memset(tlv->GetValue(), 0, tlv->GetLength());
618 
619 exit:
620     return;
621 }
622 
ReadTlvFromSecureStorage(Tlv::Type aTlvType,Crypto::Storage::KeyRef aKeyRef)623 Error Dataset::ReadTlvFromSecureStorage(Tlv::Type aTlvType, Crypto::Storage::KeyRef aKeyRef)
624 {
625     using namespace ot::Crypto::Storage;
626 
627     Error  error = kErrorNone;
628     Tlv   *tlv   = FindTlv(aTlvType);
629     size_t readLength;
630 
631     VerifyOrExit(tlv != nullptr);
632     VerifyOrExit(tlv->GetLength() > 0);
633 
634     SuccessOrExit(error = ExportKey(aKeyRef, tlv->GetValue(), tlv->GetLength(), readLength));
635     VerifyOrExit(readLength == tlv->GetLength(), error = OT_ERROR_FAILED);
636 
637 exit:
638     return error;
639 }
640 
641 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
642 
643 } // namespace MeshCoP
644 } // namespace ot
645