1 /*
2  *  Copyright (c) 2021, 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 includes definitions for Crypto Internal Trusted Storage (ITS) APIs.
32  */
33 
34 #ifndef STORAGE_HPP_
35 #define STORAGE_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/platform/crypto.h>
40 
41 #include "common/as_core_type.hpp"
42 #include "common/clearable.hpp"
43 #include "common/code_utils.hpp"
44 #include "common/error.hpp"
45 #include "common/locator.hpp"
46 #include "common/non_copyable.hpp"
47 
48 namespace ot {
49 namespace Crypto {
50 
51 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
52 
53 namespace Storage {
54 
55 /**
56  * Defines the key types.
57  */
58 enum KeyType : uint8_t
59 {
60     kKeyTypeRaw   = OT_CRYPTO_KEY_TYPE_RAW,   ///< Key Type: Raw Data.
61     kKeyTypeAes   = OT_CRYPTO_KEY_TYPE_AES,   ///< Key Type: AES.
62     kKeyTypeHmac  = OT_CRYPTO_KEY_TYPE_HMAC,  ///< Key Type: HMAC.
63     kKeyTypeEcdsa = OT_CRYPTO_KEY_TYPE_ECDSA, ///< Key Type: ECDSA.
64 };
65 
66 /**
67  * Defines the key algorithms.
68  */
69 enum KeyAlgorithm : uint8_t
70 {
71     kKeyAlgorithmVendor     = OT_CRYPTO_KEY_ALG_VENDOR,       ///< Key Algorithm: Vendor Defined.
72     kKeyAlgorithmAesEcb     = OT_CRYPTO_KEY_ALG_AES_ECB,      ///< Key Algorithm: AES ECB.
73     kKeyAlgorithmHmacSha256 = OT_CRYPTO_KEY_ALG_HMAC_SHA_256, ///< Key Algorithm: HMAC SHA-256.
74     kKeyAlgorithmEcdsa      = OT_CRYPTO_KEY_ALG_ECDSA,        ///< Key Algorithm: ECDSA.
75 };
76 
77 constexpr uint8_t kUsageNone       = OT_CRYPTO_KEY_USAGE_NONE;        ///< Key Usage: Key Usage is empty.
78 constexpr uint8_t kUsageExport     = OT_CRYPTO_KEY_USAGE_EXPORT;      ///< Key Usage: Key can be exported.
79 constexpr uint8_t kUsageEncrypt    = OT_CRYPTO_KEY_USAGE_ENCRYPT;     ///< Key Usage: Encrypt (vendor defined).
80 constexpr uint8_t kUsageDecrypt    = OT_CRYPTO_KEY_USAGE_DECRYPT;     ///< Key Usage: AES ECB.
81 constexpr uint8_t kUsageSignHash   = OT_CRYPTO_KEY_USAGE_SIGN_HASH;   ///< Key Usage: Sign Hash.
82 constexpr uint8_t kUsageVerifyHash = OT_CRYPTO_KEY_USAGE_VERIFY_HASH; ///< Key Usage: Verify Hash.
83 
84 /**
85  * Defines the key storage types.
86  */
87 enum StorageType : uint8_t
88 {
89     kTypeVolatile   = OT_CRYPTO_KEY_STORAGE_VOLATILE,   ///< Key is volatile.
90     kTypePersistent = OT_CRYPTO_KEY_STORAGE_PERSISTENT, ///< Key is persistent.
91 };
92 
93 /**
94  * This datatype represents the key reference.
95  */
96 typedef otCryptoKeyRef KeyRef;
97 
98 constexpr KeyRef kInvalidKeyRef = 0x80000000; ///< Invalid `KeyRef` value (PSA_KEY_ID_VENDOR_MAX + 1).
99 
100 /**
101  * Manages and selects the `KeyRef` values.
102  */
103 class KeyRefManager : public InstanceLocator
104 {
105 public:
106     /**
107      * Represents difference `KeyRef` types.
108      */
109     enum Type : uint8_t
110     {
111         kNetworkKey               = 1,
112         kPskc                     = 2,
113         kActiveDatasetNetworkKey  = 3,
114         kActiveDatasetPskc        = 4,
115         kPendingDatasetNetworkKey = 5,
116         kPendingDatasetPskc       = 6,
117         kEcdsa                    = 7,
118     };
119 
120     /**
121      * Initializes the `KeyRefManager`.
122      *
123      * @param[in]  aInstance     A reference to the OpenThread instance.
124      */
KeyRefManager(Instance & aInstance)125     explicit KeyRefManager(Instance &aInstance)
126         : InstanceLocator(aInstance)
127 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
128         , mExtraOffset(0)
129 #endif
130     {
131     }
132 
133     /**
134      * Determines the `KeyRef` to use for a given `Type`.
135      *
136      * @param[in] aType  The key ref type.
137      *
138      * @returns The `KeyRef` associated with @p aType.
139      */
KeyRefFor(Type aType)140     KeyRef KeyRefFor(Type aType)
141     {
142         KeyRef keyRef = kPsaItsNvmOffset + aType;
143 
144 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
145         keyRef += mExtraOffset;
146 #endif
147         return keyRef;
148     }
149 
150     /**
151      * Delete all the persistent keys.
152      */
153     void DestroyPersistentKeys(void);
154 
155 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
156     static constexpr uint32_t kKeyRefExtraOffset = 32; ///< Recommended extra offset to use.
157 
158     /**
159      * Sets the additional `KeyRef` offset value to use when determining the `KeyRef`s.
160      *
161      * This is intended for when `MULTIPLE_INSTANCE_ENABLE` is enabled to ensure different `ot::Instance`s use
162      * different `KeyRef` value ranges.
163      *
164      * @param[in] aOffset  The offset value.
165      */
SetKeyRefExtraOffset(uint32_t aOffset)166     void SetKeyRefExtraOffset(uint32_t aOffset) { mExtraOffset = aOffset; }
167 #endif
168 
169 private:
170     static constexpr KeyRef kPsaItsNvmOffset = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET;
171 
172 #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
173     uint32_t mExtraOffset;
174 #endif
175 };
176 
177 /**
178  * Determine if a given `KeyRef` is valid or not.
179  *
180  * @param[in] aKeyRef   The `KeyRef` to check.
181  *
182  * @retval TRUE   If @p aKeyRef is valid.
183  * @retval FALSE  If @p aKeyRef is not valid.
184  */
IsKeyRefValid(KeyRef aKeyRef)185 inline bool IsKeyRefValid(KeyRef aKeyRef) { return (aKeyRef < kInvalidKeyRef); }
186 
187 /**
188  * Import a key into PSA ITS.
189  *
190  * @param[in,out] aKeyRef          Reference to the key ref to be used for crypto operations.
191  * @param[in]     aKeyType         Key Type encoding for the key.
192  * @param[in]     aKeyAlgorithm    Key algorithm encoding for the key.
193  * @param[in]     aKeyUsage        Key Usage encoding for the key.
194  * @param[in]     aStorageType     Key storage type.
195  * @param[in]     aKey             Actual key to be imported.
196  * @param[in]     aKeyLen          Length of the key to be imported.
197  *
198  * @retval kErrorNone          Successfully imported the key.
199  * @retval kErrorFailed        Failed to import the key.
200  * @retval kErrorInvalidArgs   @p aKey was set to `nullptr`.
201  */
ImportKey(KeyRef & aKeyRef,KeyType aKeyType,KeyAlgorithm aKeyAlgorithm,int aKeyUsage,StorageType aStorageType,const uint8_t * aKey,size_t aKeyLen)202 inline Error ImportKey(KeyRef        &aKeyRef,
203                        KeyType        aKeyType,
204                        KeyAlgorithm   aKeyAlgorithm,
205                        int            aKeyUsage,
206                        StorageType    aStorageType,
207                        const uint8_t *aKey,
208                        size_t         aKeyLen)
209 {
210     return otPlatCryptoImportKey(&aKeyRef, static_cast<otCryptoKeyType>(aKeyType),
211                                  static_cast<otCryptoKeyAlgorithm>(aKeyAlgorithm), aKeyUsage,
212                                  static_cast<otCryptoKeyStorage>(aStorageType), aKey, aKeyLen);
213 }
214 
215 /**
216  * Export a key stored in PSA ITS.
217  *
218  * @param[in]   aKeyRef        The key ref to be used for crypto operations.
219  * @param[out]  aBuffer        Pointer to the buffer where key needs to be exported.
220  * @param[in]   aBufferLen     Length of the buffer passed to store the exported key.
221  * @param[out]  aKeyLen        Reference to variable to return the length of the exported key.
222  *
223  * @retval kErrorNone          Successfully exported  @p aKeyRef.
224  * @retval kErrorFailed        Failed to export @p aKeyRef.
225  * @retval kErrorInvalidArgs   @p aBuffer was `nullptr`.
226  */
ExportKey(KeyRef aKeyRef,uint8_t * aBuffer,size_t aBufferLen,size_t & aKeyLen)227 inline Error ExportKey(KeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t &aKeyLen)
228 {
229     return otPlatCryptoExportKey(aKeyRef, aBuffer, aBufferLen, &aKeyLen);
230 }
231 
232 /**
233  * Destroy a key stored in PSA ITS.
234  *
235  * @param[in]   aKeyRef   The key ref to be removed.
236  */
DestroyKey(KeyRef aKeyRef)237 inline void DestroyKey(KeyRef aKeyRef)
238 {
239     if (IsKeyRefValid(aKeyRef))
240     {
241         IgnoreError(otPlatCryptoDestroyKey(aKeyRef));
242     }
243 }
244 
245 /**
246  * Check if the keyRef passed has an associated key in PSA ITS.
247  *
248  * @param[in]  aKeyRef          The Key Ref for to check.
249  *
250  * @retval true                 Key Ref passed has a key associated in PSA.
251  * @retval false                Key Ref passed is invalid and has no key associated in PSA.
252  */
HasKey(KeyRef aKeyRef)253 inline bool HasKey(KeyRef aKeyRef) { return otPlatCryptoHasKey(aKeyRef); }
254 
255 } // namespace Storage
256 
257 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
258 
259 /**
260  * Represents a crypto key.
261  *
262  * The `Key` can represent a literal key (i.e., a pointer to a byte array containing the key along with a key length)
263  * or a `KeyRef` (if `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` is enabled).
264  */
265 class Key : public otCryptoKey, public Clearable<Key>
266 {
267 public:
268     /**
269      * Sets the `Key` as a literal key from a given byte array and length.
270      *
271      * @param[in] aKeyBytes   A pointer to buffer containing the key.
272      * @param[in] aKeyLength  The key length (number of bytes in @p aKeyBytes).
273      */
Set(const uint8_t * aKeyBytes,uint16_t aKeyLength)274     void Set(const uint8_t *aKeyBytes, uint16_t aKeyLength)
275     {
276         mKey       = aKeyBytes;
277         mKeyLength = aKeyLength;
278     }
279 
280     /**
281      * Gets the pointer to the bye array containing the key.
282      *
283      * If `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` is enabled and `IsKeyRef()` returns `true`, then this
284      * method returns `nullptr`.
285      *
286      * @returns The pointer to the byte array containing the key, or `nullptr` if the `Key` represents a `KeyRef`
287      */
GetBytes(void) const288     const uint8_t *GetBytes(void) const { return mKey; }
289 
290     /**
291      * Gets the key length (number of bytes).
292      *
293      * If `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` is enabled and `IsKeyRef()` returns `true`, then this
294      * method returns zero.
295      *
296      * @returns The key length (number of bytes in the byte array from `GetBytes()`), or zero if `Key` represents a
297      *          `keyRef`.
298      */
GetLength(void) const299     uint16_t GetLength(void) const { return mKeyLength; }
300 
301 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
302     /**
303      * Indicates whether or not the key is represented as a `KeyRef`.
304      *
305      * @retval TRUE  The `Key` represents a `KeyRef`
306      * @retval FALSE The `Key` represents a literal key.
307      */
IsKeyRef(void) const308     bool IsKeyRef(void) const { return (mKey == nullptr); }
309 
310     /**
311      * Gets the `KeyRef`.
312      *
313      * MUST be used when `IsKeyRef()` returns `true`, otherwise its behavior is undefined.
314      *
315      * @returns The `KeyRef` associated with `Key`.
316      */
GetKeyRef(void) const317     Storage::KeyRef GetKeyRef(void) const { return mKeyRef; }
318 
319     /**
320      * Sets the `Key` as a `KeyRef`.
321      *
322      * @param[in] aKeyRef   The `KeyRef` to set from.
323      */
SetAsKeyRef(Storage::KeyRef aKeyRef)324     void SetAsKeyRef(Storage::KeyRef aKeyRef)
325     {
326         mKey       = nullptr;
327         mKeyLength = 0;
328         mKeyRef    = aKeyRef;
329     }
330 
331     /**
332      * Extracts and return the literal key when the key is represented as a `KeyRef`
333      *
334      * MUST be used when `IsKeyRef()` returns `true`.
335      *
336      * @param[out]     aKeyBuffer  Pointer to a byte array buffer to place the extracted key.
337      * @param[in,out]  aKeyLength  On input, the size of @p aKeyBuffer.
338      *                             On exit, returns the key length (number of bytes written in @p aKeyBuffer).
339      *
340      * @retval kErrorNone    Successfully extracted the key, @p aKeyBuffer and @p aKeyLength are updated.
341      * @retval kErrorNoBufs  Key does not fit in @p aKeyBuffer (extracted key length is larger than @p aKeyLength).
342      */
343     Error ExtractKey(uint8_t *aKeyBuffer, uint16_t &aKeyLength) const;
344 #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
345 };
346 
347 /**
348  * Represents a literal key derived from a `Key`.
349  */
350 class LiteralKey : public Clearable<LiteralKey>, private NonCopyable
351 {
352 public:
353     static constexpr uint16_t kMaxSize = 32; ///< Maximum size of the key.
354 
355     /**
356      * Initializes the `LiteralKey` from a given `Key`.
357      *
358      * If the @p aKey is itself represents a literal key the same key buffer pointers are used. If the @p aKey is
359      * a `KeyRef` then the literal key is extracted. In this case, the extracted key MUST be smaller than `kMaxSize`.
360      *
361      * @param[in] aKey   The key to convert from.
362      */
363     explicit LiteralKey(const Key &aKey);
364 
365     /*
366      * Gets the pointer to the byte array containing the literal key.
367      *
368      * @returns The pointer to the byte array containing the literal key.
369      */
GetBytes(void) const370     const uint8_t *GetBytes(void) const { return mKey; }
371 
372     /**
373      * Gets the key length.
374      *
375      * @returns The key length (number of bytes in the byte array from `GetBytes()`).
376      */
GetLength(void) const377     uint16_t GetLength(void) const { return mLength; }
378 
379 private:
380     const uint8_t *mKey;
381     uint16_t       mLength;
382 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
383     uint8_t mBuffer[kMaxSize];
384 #endif
385 };
386 
387 } // namespace Crypto
388 
389 DefineCoreType(otCryptoKey, Crypto::Key);
390 
391 } // namespace ot
392 
393 #endif // STORAGE_HPP_
394