1 /*
2  * Copyright 2020,2023 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_common.h"
10 #include "fsl_puf_v3.h"
11 #include "fsl_clock.h"
12 #include "fsl_reset.h"
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.puf_v3"
20 #endif
21 
22 #define kPUF_OperationInProgress (0x0u)
23 #define kPUF_Enroll              (0x1u)
24 #define kPUF_Start               (0x2u)
25 #define kPUF_Stop                (0x5u)
26 #define kPUF_GetKey              (0x6u)
27 #define kPUF_Unwrap              (0x7u)
28 #define kPUF_WrapGeneratedRandom (0x8u)
29 #define kPUF_Wrap                (0x9u)
30 #define kPUF_GenerateRandom      (0xfu)
31 #define kPUF_Test                (0x1fu)
32 #define kPUF_Init                (0x20u)
33 #define kPUF_Zeroize             (0x2fu)
34 typedef uint32_t puf_last_operation_t;
35 
36 #define PUF_KEY_OPERATION_CONTEXT_TYPE (0x10UL << 16UL)
37 #define PUF_CONTEXT_GENERIC_KEY_TYPE   (0x0u)
38 #define PUF_CONTEXT_KEY_LEN_MASK       (0x1fffu)
39 
40 /*******************************************************************************
41  * Code
42  ******************************************************************************/
43 
puf_waitForInit(PUF_Type * base)44 static status_t puf_waitForInit(PUF_Type *base)
45 {
46     status_t status = kStatus_Fail;
47 
48     /* wait until status register reads non-zero. All zero is not valid. It should be BUSY or OK or ERROR */
49     while (0u == base->SR)
50     {
51     }
52 
53     /* wait if busy */
54     while ((base->SR & PUF_SR_BUSY_MASK) != 0u)
55     {
56     }
57 
58     /* return status */
59     if (0U != (base->SR & (PUF_SR_OK_MASK | PUF_SR_ERROR_MASK)))
60     {
61         status = kStatus_Success;
62     }
63 
64     return status;
65 }
66 
puf_powerOn(PUF_Type * base,puf_config_t * conf)67 static void puf_powerOn(PUF_Type *base, puf_config_t *conf)
68 {
69 #if defined(PUF_PUF_MEM_CTRL_POWERON_MASK)
70     base->PUF_MEM_CTRL |= PUF_PUF_MEM_CTRL_POWERON_MASK;
71 #elif defined(PUF_SRAM_CFG_ENABLE_MASK)
72     /* Power On PUF SRAM */
73     base->SRAM_CFG = 0x1u;
74     while (0u == (PUF_SRAM_STATUS_READY_MASK & base->SRAM_STATUS))
75     {
76     }
77 #else
78 #warning "No valid PUF power up definition"
79 #endif
80 }
81 
puf_powerCycle(PUF_Type * base,puf_config_t * conf)82 static status_t puf_powerCycle(PUF_Type *base, puf_config_t *conf)
83 {
84     /* Power off */
85 #if defined(PUF_PUF_MEM_CTRL_POWERON_MASK)
86     base->PUF_MEM_CTRL &= ~PUF_PUF_MEM_CTRL_POWERON_MASK;
87 #elif defined(PUF_SRAM_CFG_ENABLE_MASK)
88     base->SRAM_CFG = 0x0u;
89 #else
90 #warning "No valid PUF power up definition"
91 #endif
92 
93 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && FSL_FEATURE_PUF_HAS_NO_RESET)
94     /* Reset PUF and reenable power to PUF SRAM */
95     RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
96 #endif /* !FSL_FEATURE_PUF_HAS_NO_RESET */
97     puf_powerOn(base, conf);
98 
99     return kStatus_Success;
100 }
101 
puf_makeStatus(PUF_Type * base,puf_last_operation_t operation)102 static status_t puf_makeStatus(PUF_Type *base, puf_last_operation_t operation)
103 {
104     uint32_t result;
105     status_t status = kStatus_Fail;
106 
107     if (((base->ORR & PUF_ORR_LAST_OPERATION_MASK) >> PUF_ORR_LAST_OPERATION_SHIFT) == operation)
108     {
109         result = (base->ORR & PUF_ORR_RESULT_CODE_MASK);
110         if ((result == kPUF_ResultOK) && (0u == (base->SR & PUF_SR_ERROR_MASK)))
111         {
112             status = kStatus_Success;
113         }
114         else
115         {
116             status = MAKE_STATUS((int32_t)kStatusGroup_PUF, (int32_t)result);
117         }
118     }
119 
120     return status;
121 }
122 
123 /*!
124  * brief Sets the default configuration of PUF
125  *
126  * This function initialize PUF config structure to default values.
127  *
128  * @param conf PUF configuration structure
129  */
PUF_GetDefaultConfig(puf_config_t * conf)130 void PUF_GetDefaultConfig(puf_config_t *conf)
131 {
132     /* Default configuration after reset */
133     conf->dataEndianness = kPUF_EndianBig;
134     conf->CKGATING       = 0U;
135 }
136 
137 /*!
138  * brief Initialize PUF
139  *
140  * This function enables power to PUF block and waits until the block initializes.
141  *
142  * @param conf PUF configuration structure
143  * @return Status of the init operation
144  */
PUF_Init(PUF_Type * base,puf_config_t * conf)145 status_t PUF_Init(PUF_Type *base, puf_config_t *conf)
146 {
147     status_t status = kStatus_Fail;
148 
149     /* Enable PUF clock */
150     CLOCK_EnableClock(kCLOCK_Puf);
151 
152 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && FSL_FEATURE_PUF_HAS_NO_RESET)
153     /* Reset PUF */
154     RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
155 #endif /* !FSL_FEATURE_PUF_HAS_NO_RESET */
156 
157 #if defined(PUF_SRAM_CFG_CKGATING_MASK)
158     /* Set configuration from SRAM */
159     base->SRAM_CFG |= PUF_SRAM_CFG_CKGATING(conf->CKGATING);
160 #endif /* defined(PUF_SRAM_CFG_CKGATING_MASK) */
161 
162     /* Enable power to PUF SRAM */
163     puf_powerOn(base, conf);
164 
165     /* Wait for peripheral to become ready */
166     status = puf_waitForInit(base);
167 
168     /* In case of error or enroll & start not allowed, do power-cycle */
169     if ((status != kStatus_Success) || ((PUF_AR_ALLOW_ENROLL_MASK | PUF_AR_ALLOW_START_MASK) !=
170                                         (base->AR & (PUF_AR_ALLOW_ENROLL_MASK | PUF_AR_ALLOW_START_MASK))))
171     {
172         (void)puf_powerCycle(base, conf);
173         status = puf_waitForInit(base);
174     }
175 
176     if (kStatus_Success == status)
177     {
178         /* Set data endianness */
179         base->MISC = PUF_MISC_DATA_ENDIANNESS(conf->dataEndianness);
180 
181         /* get status */
182         status = puf_makeStatus(base, kPUF_Init);
183     }
184 
185     return status;
186 }
187 
188 /*!
189  * brief Denitialize PUF
190  *
191  * This function disables power to PUF SRAM and peripheral clock.
192  *
193  * @param base PUF peripheral base address
194  * @param conf PUF configuration structure
195  */
PUF_Deinit(PUF_Type * base,puf_config_t * conf)196 void PUF_Deinit(PUF_Type *base, puf_config_t *conf)
197 {
198 #if defined(PUF_PUF_MEM_CTRL_POWERON_MASK)
199     base->PUF_MEM_CTRL &= ~PUF_PUF_MEM_CTRL_POWERON_MASK;
200 #elif defined(PUF_SRAM_CFG_ENABLE_MASK)
201     base->SRAM_CFG = 0x0u;
202 #else
203 #warning "No valid PUF power up definition"
204 #endif
205 
206 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && FSL_FEATURE_PUF_HAS_NO_RESET)
207     RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
208 #endif /* !FSL_FEATURE_PUF_HAS_NO_RESET */
209     CLOCK_DisableClock(kCLOCK_Puf);
210 }
211 
212 /*!
213  * brief Enroll PUF
214  *
215  * This function derives a digital fingerprint, generates the corresponding Activation Code (AC)
216  * and returns it to be stored in an NVM or a file. This step needs to be
217  * performed only once for each device. This function may be permanently disallowed by a fuse.
218  *
219  * @param base PUF peripheral base address
220  * @param[out] activationCode Word aligned address of the resulting activation code.
221  * @param activationCodeSize Size of the activationCode buffer in bytes. Shall be FSL_FEATURE_PUF_ACTIVATION_CODE_SIZE
222  * bytes.
223  * @param score Value of the PUF Score that was obtained during the enroll operation.
224  * @return Status of enroll operation.
225  */
PUF_Enroll(PUF_Type * base,uint8_t * activationCode,size_t activationCodeSize,uint8_t * score)226 status_t PUF_Enroll(PUF_Type *base, uint8_t *activationCode, size_t activationCodeSize, uint8_t *score)
227 {
228     status_t status                 = kStatus_Fail;
229     uint32_t *activationCodeAligned = NULL;
230     register uint32_t temp32        = 0;
231 
232     /* check that activation code buffer size is at least FSL_FEATURE_PUF_ACTIVATION_CODE_SIZE bytes */
233     if (activationCodeSize < PUF_ACTIVATION_CODE_SIZE)
234     {
235         return kStatus_InvalidArgument;
236     }
237 
238     /* only work with aligned and valid activationCode */
239     if ((0U != (0x3u & (uintptr_t)activationCode)) || (activationCode == NULL))
240     {
241         return kStatus_InvalidArgument;
242     }
243 
244     activationCodeAligned = (uint32_t *)(uintptr_t)activationCode;
245 
246     /* check if ENROLL is allowed */
247     if (0x0u == (base->AR & PUF_AR_ALLOW_ENROLL_MASK))
248     {
249         return kStatus_PUF_OperationNotAllowed;
250     }
251 
252     /* begin */
253     base->CR = PUF_CR_ENROLL_MASK;
254 
255     /* wait till command is accepted */
256     while (0u != (base->CR & PUF_CR_ENROLL_MASK))
257     {
258     }
259 
260     /* read out AC */
261     while (0u != (base->SR & PUF_SR_BUSY_MASK))
262     {
263         if (0u != (PUF_SR_DO_REQUEST_MASK & base->SR))
264         {
265             temp32 = base->DOR;
266             if (activationCodeSize >= sizeof(uint32_t))
267             {
268                 *activationCodeAligned = temp32;
269                 activationCodeAligned++;
270                 activationCodeSize -= sizeof(uint32_t);
271             }
272         }
273     }
274 
275     /* In case of success fill in score */
276     if ((0u != (base->SR & PUF_SR_OK_MASK)) && (score != NULL))
277     {
278         *score = (uint8_t)(base->PSR & PUF_PSR_PUF_SCORE_MASK);
279     }
280 
281     /* get status */
282     status = puf_makeStatus(base, kPUF_Enroll);
283 
284     return status;
285 }
286 
287 /*!
288  * brief Start PUF
289  *
290  * The Activation Code generated during the Enroll operation is used to
291  * reconstruct the digital fingerprint. This needs to be done after every power-up
292  * and reset.
293  *
294  * @param base PUF peripheral base address
295  * @param[in] activationCode Word aligned address of the input activation code.
296  * @param activationCodeSize Size of the activationCode buffer in bytes. Shall be FSL_FEATURE_PUF_ACTIVATION_CODE_SIZE
297  * bytes.
298  * @param score Value of the PUF Score that was obtained during the start operation.
299  * return Status of start operation.
300  */
PUF_Start(PUF_Type * base,const uint8_t * activationCode,size_t activationCodeSize,uint8_t * score)301 status_t PUF_Start(PUF_Type *base, const uint8_t *activationCode, size_t activationCodeSize, uint8_t *score)
302 {
303     status_t status                       = kStatus_Fail;
304     const uint32_t *activationCodeAligned = NULL;
305     register uint32_t temp32              = 0;
306 
307     /* check that activation code size is at least FSL_FEATURE_PUF_ACTIVATION_CODE_SIZE bytes */
308     if (activationCodeSize < PUF_ACTIVATION_CODE_SIZE)
309     {
310         return kStatus_InvalidArgument;
311     }
312 
313     /* Set activationCodeSize to FSL_FEATURE_PUF_ACTIVATION_CODE_SIZE bytes */
314     activationCodeSize = PUF_ACTIVATION_CODE_SIZE;
315 
316     /* only work with aligned activationCode */
317     if ((0U != (0x3u & (uintptr_t)activationCode)) || (activationCode == NULL))
318     {
319         return kStatus_InvalidArgument;
320     }
321 
322     activationCodeAligned = (const uint32_t *)(uintptr_t)activationCode;
323 
324     /* check if START is allowed */
325     if (0x0u == (base->AR & PUF_AR_ALLOW_START_MASK))
326     {
327         return kStatus_PUF_OperationNotAllowed;
328     }
329 
330     /* begin */
331     base->CR = PUF_CR_START_MASK;
332 
333     /* wait till command is accepted */
334     while (0u != (base->CR & PUF_CR_START_MASK))
335     {
336     }
337 
338     /* while busy send AC */
339     while (0u != (base->SR & PUF_SR_BUSY_MASK))
340     {
341         if (0u != (PUF_SR_DI_REQUEST_MASK & base->SR))
342         {
343             if (activationCodeSize >= sizeof(uint32_t))
344             {
345                 temp32 = *activationCodeAligned;
346                 activationCodeAligned++;
347                 activationCodeSize -= sizeof(uint32_t);
348             }
349             /* Send AC again */
350             else
351             {
352                 activationCodeAligned = (const uint32_t *)(uintptr_t)activationCode;
353                 temp32                = *activationCodeAligned;
354                 activationCodeAligned++;
355                 activationCodeSize = PUF_ACTIVATION_CODE_SIZE - sizeof(uint32_t);
356             }
357             base->DIR = temp32;
358         }
359     }
360 
361     /* In case of success fill in score */
362     if ((0u != (base->SR & PUF_SR_OK_MASK)) && (score != NULL))
363     {
364         *score = (uint8_t)(base->PSR & PUF_PSR_PUF_SCORE_MASK);
365     }
366 
367     /* get status */
368     status = puf_makeStatus(base, kPUF_Start);
369 
370     return status;
371 }
372 
373 /*!
374  * brief Stop PUF
375  *
376  * The Stop operation removes all key material from PUF flipflops and PUF SRAM, and sets
377  * PUF to the Stopped state.
378  *
379  * @param base PUF peripheral base address
380  * @return Status of stop operation.
381  */
PUF_Stop(PUF_Type * base)382 status_t PUF_Stop(PUF_Type *base)
383 {
384     status_t status = kStatus_Fail;
385 
386     /* check if STOP is allowed */
387     if (0x0u == (base->AR & PUF_AR_ALLOW_STOP_MASK))
388     {
389         return kStatus_PUF_OperationNotAllowed;
390     }
391 
392     /* begin */
393     base->CR = PUF_CR_STOP_MASK;
394 
395     /* wait till command is accepted */
396     while (0u != (base->CR & PUF_CR_STOP_MASK))
397     {
398     }
399 
400     /* wait while busy */
401     while (0u != (base->SR & PUF_SR_BUSY_MASK))
402     {
403     }
404 
405     /* get status */
406     status = puf_makeStatus(base, kPUF_Stop);
407 
408     return status;
409 }
410 
411 /*!
412  * brief PUF Get Key
413  *
414  * The Get Key operation derives a key from the intrinsic PUF key and externally provided context.
415  *
416  * @param base PUF peripheral base address
417  * @param keyCtx PUF key context struct
418  * @param keyDest output destination of the derived PUF key
419  * @param[out] key Word aligned address of output key (only used when kPUF_KeyDestRegister).
420  * @param keySize Size of the derived key in bytes.
421  * @return Status of get key operation.
422  */
PUF_GetKey(PUF_Type * base,puf_key_ctx_t * keyCtx,puf_key_dest_t keyDest,uint8_t * key,size_t keySize)423 status_t PUF_GetKey(PUF_Type *base, puf_key_ctx_t *keyCtx, puf_key_dest_t keyDest, uint8_t *key, size_t keySize)
424 {
425     uint8_t idx          = 0;
426     uint32_t *keyAligned = NULL;
427     uint32_t context[4]  = {0};
428     status_t status      = kStatus_Fail;
429 
430     /* check if GET KEY is allowed */
431     if (0x0u == (base->AR & PUF_AR_ALLOW_GET_KEY_MASK))
432     {
433         return kStatus_PUF_OperationNotAllowed;
434     }
435 
436     /* check for key context */
437     if (keyCtx == NULL)
438     {
439         return kStatus_InvalidArgument;
440     }
441 
442     /* check for valid key destination */
443     if (((keyDest == kPUF_KeyDestRegister) && (key == NULL)) || (keyDest == kPUF_KeyDestInvalid))
444     {
445         return kStatus_InvalidArgument;
446     }
447 
448     /* check for valid key size. */
449     /* must be 8byte multiple */
450     if (0U != (keySize & 0x7u))
451     {
452         return kStatus_InvalidArgument;
453     }
454     /* if keySize > 128bytes, it must be equal to 256bytes or 384bytes or 512bytes */
455     if ((keySize > 128u) && !((keySize == 256u) || (keySize == 384u) || (keySize == 512u)))
456     {
457         return kStatus_InvalidArgument;
458     }
459 
460     /* only work with aligned key */
461     if (0U != (0x3u & (uintptr_t)key))
462     {
463         return kStatus_InvalidArgument;
464     }
465 
466     keyAligned = (uint32_t *)(uintptr_t)key;
467 
468     /* fill in key context */
469     context[0] = PUF_KEY_OPERATION_CONTEXT_TYPE | ((keySize * 8u) & PUF_CONTEXT_KEY_LEN_MASK);
470     context[1] = PUF_CONTEXT_GENERIC_KEY_TYPE | (keyCtx->keyScopeStarted << 8u) | keyCtx->keyScopeEnrolled;
471     context[2] = keyCtx->userCtx0;
472     context[3] = keyCtx->userCtx1;
473 
474     /* set key destination */
475     base->DATA_DEST = keyDest;
476 
477     /* begin */
478     base->CR = PUF_CR_GET_KEY_MASK;
479 
480     /* wait till command is accepted */
481     while (0u != (base->CR & PUF_CR_GET_KEY_MASK))
482     {
483     }
484 
485     /* send context and read output data while busy */
486     while (0U != (base->SR & PUF_SR_BUSY_MASK))
487     {
488         if ((0U != (PUF_SR_DI_REQUEST_MASK & base->SR)) && (idx < 4u))
489         {
490             base->DIR = context[idx];
491             idx++;
492         }
493 
494         if ((0U != (PUF_SR_DO_REQUEST_MASK & base->SR)) && (kPUF_KeyDestRegister == keyDest))
495         {
496             if (keySize >= sizeof(uint32_t))
497             {
498                 *keyAligned = base->DOR;
499                 keyAligned++;
500                 keySize -= sizeof(uint32_t);
501             }
502         }
503     }
504 
505     /* get status */
506     status = puf_makeStatus(base, kPUF_GetKey);
507 
508     return status;
509 }
510 
511 /*!
512  * brief PUF Wrap generated random
513  *
514  * The Wrap Generated Random operation wraps a random key into a Key Code (KC).
515  *
516  * @param base PUF peripheral base address
517  * @param keyCtx PUF key context struct
518  * @param keySize Size of the key to be generated in bytes.
519  * @param[out] keyCode Word aligned address of the resulting key code.
520  * @param keyCodeSize Size of the output keycode in bytes.
521  * @return Status of wrap generated random operation.
522  */
PUF_WrapGeneratedRandom(PUF_Type * base,puf_key_ctx_t * keyCtx,size_t keySize,uint8_t * keyCode,size_t keyCodeSize)523 status_t PUF_WrapGeneratedRandom(
524     PUF_Type *base, puf_key_ctx_t *keyCtx, size_t keySize, uint8_t *keyCode, size_t keyCodeSize)
525 {
526     uint8_t idx              = 0;
527     uint32_t *keyCodeAligned = NULL;
528     uint32_t context[4]      = {0};
529     status_t status          = kStatus_Fail;
530 
531     /* check if WRAP GENERATED RANDOM is allowed */
532     if (0x0u == (base->AR & PUF_AR_ALLOW_WRAP_GENERATED_RANDOM_MASK))
533     {
534         return kStatus_PUF_OperationNotAllowed;
535     }
536 
537     /* check for valid key context and keyCode buffer */
538     if ((keyCtx == NULL) || (keyCode == NULL))
539     {
540         return kStatus_InvalidArgument;
541     }
542 
543     /* check for valid key size. */
544     /* must be 8byte multiple */
545     if (0U != (keySize & 0x7u))
546     {
547         return kStatus_InvalidArgument;
548     }
549     /* if keySize > 128bytes, it must be equal to 256bytes or 384bytes or 512bytes */
550     if ((keySize > 128u) && !((keySize == 256u) || (keySize == 384u) || (keySize == 512u)))
551     {
552         return kStatus_InvalidArgument;
553     }
554 
555     /* check that keyCodeSize is correct for given keySize */
556     if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize))
557     {
558         return kStatus_InvalidArgument;
559     }
560 
561     /* only work with aligned key code */
562     if (0U != (0x3u & (uintptr_t)keyCode))
563     {
564         return kStatus_InvalidArgument;
565     }
566 
567     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
568 
569     /* fill in key context */
570     context[0] = PUF_KEY_OPERATION_CONTEXT_TYPE | ((keySize * 8u) & 0x1FFFu);
571     context[1] = PUF_CONTEXT_GENERIC_KEY_TYPE | (keyCtx->keyScopeStarted << 8u) | keyCtx->keyScopeEnrolled;
572     context[2] = keyCtx->userCtx0;
573     context[3] = keyCtx->userCtx1;
574 
575     /* begin */
576     base->CR = PUF_CR_WRAP_GENERATED_RANDOM_MASK;
577 
578     /* wait till command is accepted */
579     while (0u != (base->CR & PUF_CR_WRAP_GENERATED_RANDOM_MASK))
580     {
581     }
582 
583     /* send context and read output data while busy */
584     while (0u != (base->SR & PUF_SR_BUSY_MASK))
585     {
586         if ((0u != (PUF_SR_DI_REQUEST_MASK & base->SR)) && (idx < 4u))
587         {
588             base->DIR = context[idx];
589             idx++;
590         }
591 
592         if (0u != (PUF_SR_DO_REQUEST_MASK & base->SR))
593         {
594             if (keyCodeSize >= sizeof(uint32_t))
595             {
596                 *keyCodeAligned = base->DOR;
597                 keyCodeAligned++;
598                 keyCodeSize -= sizeof(uint32_t);
599             }
600         }
601     }
602 
603     /* get status */
604     status = puf_makeStatus(base, kPUF_WrapGeneratedRandom);
605 
606     return status;
607 }
608 
609 /*!
610  * brief PUF Wrap user key
611  *
612  * The Wrap operation wraps a user defined key into a Key Code (KC).
613  *
614  * @param base PUF peripheral base address
615  * @param keyCtx PUF key context struct.
616  * @param userKey Word aligned address of input user key.
617  * @param userKeySize Size of the key to be wrapped in bytes.
618  * @param[out] keyCode Word aligned address of the resulting key code.
619  * @param keyCodeSize Size of the output keycode in bytes.
620  * @return Status of wrap operation.
621  */
PUF_Wrap(PUF_Type * base,puf_key_ctx_t * keyCtx,uint8_t * userKey,size_t userKeySize,uint8_t * keyCode,size_t keyCodeSize)622 status_t PUF_Wrap(
623     PUF_Type *base, puf_key_ctx_t *keyCtx, uint8_t *userKey, size_t userKeySize, uint8_t *keyCode, size_t keyCodeSize)
624 {
625     uint8_t ctxIdx           = 0;
626     uint32_t *userKeyAligned = NULL;
627     uint32_t *keyCodeAligned = NULL;
628     uint32_t context[4]      = {0};
629     status_t status          = kStatus_Fail;
630 
631     /* check if WRAP is allowed */
632     if (0x0u == (base->AR & PUF_AR_ALLOW_WRAP_MASK))
633     {
634         return kStatus_PUF_OperationNotAllowed;
635     }
636 
637     /* check for valid keyCtx and keyCode pointers */
638     if ((keyCtx == NULL) || (keyCode == NULL))
639     {
640         return kStatus_InvalidArgument;
641     }
642 
643     /* check for valid userKey size. */
644     /* must be 8byte multiple */
645     if (0U != (userKeySize & 0x7u))
646     {
647         return kStatus_InvalidArgument;
648     }
649     /* if userKeySize > 128bytes, it must be equal to 256bytes or 384bytes or 512bytes */
650     if ((userKeySize > 128u) && !((userKeySize == 256u) || (userKeySize == 384u) || (userKeySize == 512u)))
651     {
652         return kStatus_InvalidArgument;
653     }
654 
655     /* check that keyCodeSize is correct for given userKeySize */
656     if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize))
657     {
658         return kStatus_InvalidArgument;
659     }
660 
661     /* only work with aligned userKey and key code */
662     if (0U != ((0x3u & (uintptr_t)userKey)) || (0U != (0x3u & (uintptr_t)keyCode)))
663     {
664         return kStatus_InvalidArgument;
665     }
666 
667     userKeyAligned = (uint32_t *)(uintptr_t)userKey;
668     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
669 
670     /* fill in key context */
671     context[0] = PUF_KEY_OPERATION_CONTEXT_TYPE | ((userKeySize * 8u) & 0x1FFFu);
672     context[1] = PUF_CONTEXT_GENERIC_KEY_TYPE | (keyCtx->keyScopeStarted << 8u) | keyCtx->keyScopeEnrolled;
673     context[2] = keyCtx->userCtx0;
674     context[3] = keyCtx->userCtx1;
675 
676     /* begin */
677     base->CR = PUF_CR_WRAP_MASK;
678 
679     /* wait till command is accepted */
680     while (0u != (base->CR & PUF_CR_WRAP_MASK))
681     {
682     }
683 
684     /* send context and read output data while busy */
685     while (0u != (base->SR & PUF_SR_BUSY_MASK))
686     {
687         if (0u != (PUF_SR_DI_REQUEST_MASK & base->SR))
688         {
689             /* send context first */
690             if (ctxIdx < 4u)
691             {
692                 base->DIR = context[ctxIdx];
693                 ctxIdx++;
694             }
695             /* send userKey */
696             else
697             {
698                 base->DIR = *userKeyAligned;
699                 userKeyAligned++;
700             }
701         }
702 
703         if (0u != (PUF_SR_DO_REQUEST_MASK & base->SR))
704         {
705             if (keyCodeSize >= sizeof(uint32_t))
706             {
707                 *keyCodeAligned = base->DOR;
708                 keyCodeAligned++;
709                 keyCodeSize -= sizeof(uint32_t);
710             }
711         }
712     }
713 
714     /* get status */
715     status = puf_makeStatus(base, kPUF_Wrap);
716 
717     return status;
718 }
719 
720 /*!
721  * brief PUF Unwrap user key
722  *
723  * The unwrap operation unwraps the key from a previously created Key Code (KC)
724  *
725  * @param base PUF peripheral base address
726  * @param keyDest output destination of the unwraped PUF key
727  * @param[in] keyCode Word aligned address of the input key code.
728  * @param keyCodeSize Size of the input keycode in bytes.
729  * @param key Word aligned address of output key (only used when kPUF_KeyDestRegister).
730  * @param keySize Size of the key to be generated in bytes.
731  * @return Status of unwrap operation.
732  */
PUF_Unwrap(PUF_Type * base,puf_key_dest_t keyDest,uint8_t * keyCode,size_t keyCodeSize,uint8_t * key,size_t keySize)733 status_t PUF_Unwrap(
734     PUF_Type *base, puf_key_dest_t keyDest, uint8_t *keyCode, size_t keyCodeSize, uint8_t *key, size_t keySize)
735 {
736     uint32_t *keyAligned     = NULL;
737     uint32_t *keyCodeAligned = NULL;
738     status_t status          = kStatus_Fail;
739 
740     /* check if UNWRAP is allowed */
741     if (0x0u == (base->AR & PUF_AR_ALLOW_UNWRAP_MASK))
742     {
743         return kStatus_PUF_OperationNotAllowed;
744     }
745 
746     /* check for valid key destination */
747     if (((keyDest == kPUF_KeyDestRegister) && (key == NULL)) || (keyDest == kPUF_KeyDestInvalid))
748     {
749         return kStatus_InvalidArgument;
750     }
751 
752     /* only work with aligned key and key code */
753     if ((0U != (0x3u & (uintptr_t)key)) || (0U != (0x3u & (uintptr_t)keyCode)) || (keyCode == NULL))
754     {
755         return kStatus_InvalidArgument;
756     }
757 
758     keyAligned     = (uint32_t *)(uintptr_t)key;
759     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
760 
761     /* set key destination */
762     base->DATA_DEST = keyDest;
763 
764     /* begin */
765     base->CR = PUF_CR_UNWRAP_MASK;
766 
767     /* wait till command is accepted */
768     while (0u != (base->CR & PUF_CR_UNWRAP_MASK))
769     {
770     }
771 
772     /* send context and read output data while busy */
773     while (0u != (base->SR & PUF_SR_BUSY_MASK))
774     {
775         if (0u != (PUF_SR_DI_REQUEST_MASK & base->SR))
776         {
777             if (keyCodeSize >= sizeof(uint32_t))
778             {
779                 base->DIR = *keyCodeAligned;
780                 keyCodeAligned++;
781                 keyCodeSize -= sizeof(uint32_t);
782             }
783         }
784 
785         if (0u != (PUF_SR_DO_REQUEST_MASK & base->SR))
786         {
787             if (keySize >= sizeof(uint32_t))
788             {
789                 *keyAligned = base->DOR;
790                 keyAligned++;
791                 keySize -= sizeof(uint32_t);
792             }
793         }
794     }
795 
796     /* get status */
797     status = puf_makeStatus(base, kPUF_Unwrap);
798 
799     return status;
800 }
801 
802 /*!
803  * brief Generate Random
804  *
805  * The Generate Random operation outputs the requested amount of random data as specified in a
806  * provided context.
807  *
808  * @param base PUF peripheral base address
809  * @param size Size of random data to be genarated in bytes.
810  * @return Status of generate random operation.
811  */
PUF_GenerateRandom(PUF_Type * base,uint8_t * data,size_t size)812 status_t PUF_GenerateRandom(PUF_Type *base, uint8_t *data, size_t size)
813 {
814     uint32_t context;
815     uint32_t *dataAligned = NULL;
816     status_t status       = kStatus_Fail;
817 
818     if (data == NULL)
819     {
820         return kStatus_InvalidArgument;
821     }
822 
823     /* check if Generate random is allowed */
824     if (0u == (base->AR & PUF_AR_ALLOW_GENERATE_RANDOM_MASK))
825     {
826         return kStatus_PUF_OperationNotAllowed;
827     }
828 
829     /* check for valid size. */
830     /* must be 8byte multiple */
831     if (0U != (size & 0x7u))
832     {
833         return kStatus_InvalidArgument;
834     }
835     /* if size > 128bytes, it must be equal to 256bytes or 384bytes or 512bytes */
836     if ((size > 128u) && !((size == 256u) || (size == 384u) || (size == 512u)))
837     {
838         return kStatus_InvalidArgument;
839     }
840 
841     /* only work with aligned data buffer */
842     if (0U != (0x3u & (uintptr_t)data))
843     {
844         return kStatus_InvalidArgument;
845     }
846 
847     /* Configure context */
848     context = ((size * 8u) & 0x1FFFu);
849 
850     dataAligned = (uint32_t *)(uintptr_t)data;
851 
852     /* begin */
853     base->DATA_DEST = PUF_DATA_DEST_DEST_DOR_MASK;
854 
855     base->CR = PUF_CR_GENERATE_RANDOM_MASK;
856 
857     /* wait till command is accepted */
858     while (0u != (base->CR & PUF_CR_GENERATE_RANDOM_MASK))
859     {
860     }
861 
862     /* send context and read output data while busy */
863     while (0u != (base->SR & PUF_SR_BUSY_MASK))
864     {
865         if (0u != (PUF_SR_DI_REQUEST_MASK & base->SR))
866         {
867             base->DIR = context;
868         }
869 
870         if (0u != (PUF_SR_DO_REQUEST_MASK & base->SR))
871         {
872             *dataAligned = base->DOR;
873             dataAligned++;
874         }
875     }
876 
877     /* get status */
878     status = puf_makeStatus(base, kPUF_GenerateRandom);
879 
880     return status;
881 }
882 
883 /*!
884  * brief Zeroize PUF
885  *
886  * This function clears all PUF internal logic and puts the PUF to zeroized state.
887  *
888  * @param base PUF peripheral base address
889  * @return Status of the zeroize operation.
890  */
PUF_Zeroize(PUF_Type * base)891 status_t PUF_Zeroize(PUF_Type *base)
892 {
893     status_t status = kStatus_Fail;
894 
895     /* zeroize command is always allowed */
896     base->CR = PUF_CR_ZEROIZE_MASK;
897 
898     /* wait till command is accepted */
899     while (0u != (base->CR & PUF_CR_ZEROIZE_MASK))
900     {
901     }
902 
903     /* wait while busy */
904     while (0u != (base->SR & PUF_SR_BUSY_MASK))
905     {
906     }
907 
908     /* check status */
909     if (((PUF_SR_ZEROIZED_MASK | PUF_SR_OK_MASK) == base->SR) && (0u == base->AR))
910     {
911         status = puf_makeStatus(base, kPUF_Zeroize);
912     }
913 
914     return status;
915 }
916 
917 /*!
918  * brief Test PUF
919  *
920  * With the Test PUF operation, diagnostics about the PUF quality is collected and presented in a PUF
921  * score.
922  *
923  * @param base PUF peripheral base address
924  * @param score Value of the PUF Score that was obtained during the enroll operation.
925  * @return Status of the test operation.
926  */
PUF_Test(PUF_Type * base,uint8_t * score)927 status_t PUF_Test(PUF_Type *base, uint8_t *score)
928 {
929     status_t status = kStatus_Fail;
930 
931     /* check if TEST is allowed */
932     if (0x0u == (base->AR & PUF_AR_ALLOW_TEST_PUF_MASK))
933     {
934         return kStatus_PUF_OperationNotAllowed;
935     }
936 
937     /* begin */
938     base->CR = PUF_CR_TEST_PUF_MASK;
939 
940     /* wait till command is accepted */
941     while (0u != (base->CR & PUF_CR_TEST_PUF_MASK))
942     {
943     }
944 
945     /* wait while busy */
946     while (0u != (base->SR & PUF_SR_BUSY_MASK))
947     {
948     }
949 
950     /* In case of success fill in score */
951     if ((0u != (base->SR & PUF_SR_OK_MASK)) && (score != NULL))
952     {
953         *score = (uint8_t)(base->PSR & PUF_PSR_PUF_SCORE_MASK);
954     }
955 
956     /* Check status */
957     status = puf_makeStatus(base, kPUF_Test);
958 
959     return status;
960 }
961 
962 /*!
963  * brief Set lock of PUF operation
964  *
965  * Lock the security level of PUF block until key generate, wrap or unwrap operation is completed.
966  * Note: Only secure-privilege code can change the security level.
967  *
968  * @param base PUF peripheral base address
969  * @param securityLevel Security level of PUF block.
970  * @return Status of the test operation.
971  */
PUF_SetLock(PUF_Type * base,puf_sec_level_t securityLevel)972 status_t PUF_SetLock(PUF_Type *base, puf_sec_level_t securityLevel)
973 {
974     uint32_t sec_lock_option = 0u;
975 
976     if ((securityLevel != kPUF_NonsecureUser) && (securityLevel != kPUF_NonsecurePrivilege) &&
977         (securityLevel != kPUF_SecureUser) && (securityLevel != kPUF_SecurePrivilege))
978     {
979         return kStatus_InvalidArgument;
980     }
981 
982     /* Wait until PUF is in IDLE */
983     while ((base->SR & PUF_SR_BUSY_MASK) != 0u)
984     {
985     }
986 
987     /* Prepare SEC_LOCK option word */
988     /* [1:0] - Security level */
989     /* [3:2] - anti-pole of security level [1:0] */
990     /* [15:4] - PATTERN: This field must be written as 0xAC5 */
991     sec_lock_option = SEC_LOCK_PATTERN | securityLevel;
992 
993     /* Apply setings */
994     base->SEC_LOCK = sec_lock_option;
995 
996     /* Check if the security level is same as the level written */
997     if (securityLevel != base->SEC_LOCK)
998     {
999         return kStatus_Fail;
1000     }
1001 
1002     return kStatus_Success;
1003 }
1004 
1005 /*!
1006  * brief Set App Context mask
1007  *
1008  * This function sets Application defined context mask used in conjunction with key user context 2.
1009  * Whenever bit in this register is 1, corresponding bit in user context 2 provided
1010  * during key code creation should be zero only.
1011  *
1012  * This register is only modifiable by task running at secure-privilege level.
1013  *
1014  * @param base PUF peripheral base address
1015  * @param appCtxMask Value of the Application defined context mask.
1016  * @return Status of the test operation.
1017  */
PUF_SetCtxMask(PUF_Type * base,uint32_t appCtxMask)1018 status_t PUF_SetCtxMask(PUF_Type *base, uint32_t appCtxMask)
1019 {
1020     base->APP_CTX_MASK = appCtxMask;
1021 
1022     return kStatus_Success;
1023 }
1024