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