1 /*--------------------------------------------------------------------------*/
2 /* Copyright 2020-2021 NXP                                                  */
3 /*                                                                          */
4 /* NXP Confidential. This software is owned or controlled by NXP and may    */
5 /* only be used strictly in accordance with the applicable license terms.   */
6 /* By expressly accepting such terms or by downloading, installing,         */
7 /* activating and/or otherwise using the software, you are agreeing that    */
8 /* you have read, and that you agree to comply with and are bound by, such  */
9 /* license terms. If you do not agree to be bound by the applicable license */
10 /* terms, then you may not retain, install, activate or otherwise use the   */
11 /* software.                                                                */
12 /*--------------------------------------------------------------------------*/
13 
14 /**
15  * @file mcuxClCss_Rng.c
16  * @brief CSSv2 implementation for  random number generation.
17  * This file implements the functions declared in mcuxClCss_Rng.h.
18  */
19 
20 
21 #include <mcuxClCss_Rng.h>              // Implement mcuxClCss interface "Rng"
22 #include <mcuxClMemory.h>
23 #include <mcuxCsslFlowProtection.h>
24 #include <toolchain.h>
25 #include <mcuxClCss.h>
26 #include <internal/mcuxClCss_Internal.h>
27 
28 #define RANDOM_BIT_ARRAY_SIZE 4U
29 
30 #define DRBG_TEST_MODE_INSTANTIATE ((uint32_t)0U)
31 #define DRBG_TEST_MODE_EXTRACT ((uint32_t)1U)
32 #define DRBG_TEST_MODE_AES_ECB ((uint32_t)3U)
33 #define DRBG_TEST_MODE_AES_CTR ((uint32_t)2U)
34 
35 
36 
37 // Command name change -- should move to top level platform header
38 #ifndef ID_CFG_CSS_CMD_RND_REQ
39 #define ID_CFG_CSS_CMD_RND_REQ ID_CFG_CSS_CMD_DRBG_REQ
40 #endif
41 
42 // Utility code of mcuxClCss implementation for PRNG access
43 
44 /**
45  * Gets a pseudo-random 32-bit integer from the CSS PRNG.
46  */
css_getPRNGWord(void)47 static inline uint32_t css_getPRNGWord(
48     void)
49 {
50     return IP_CSS->CSS_PRNG_DATOUT_b.PRNG_DATOUT;
51 }
52 
53 // Implementation of mcuxClCss interface "Rng"
54 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgRequest_Async)55 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgRequest_Async)
56 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgRequest_Async(
57     uint8_t * pOutput,
58     size_t outputLength)
59 {
60     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgRequest_Async);
61 
62     MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgRequest_Async, (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MIN_SIZE > outputLength) ||
63                                                                          (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MAX_SIZE < outputLength) ||
64                                                                          (0U != outputLength % 4U));
65 
66     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
67     if (MCUXCLCSS_ISBUSY)
68     {
69         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgRequest_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
70     }
71 
72     MCUXCLCSS_SETCSSOUTPUT(pOutput, outputLength);
73 
74     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_RND_REQ, 0U, CSS_CMD_LITTLE_ENDIAN);
75 
76     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgRequest_Async, MCUXCLCSS_STATUS_OK_WAIT);
77 }
78 
79 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestInstantiate_Async)80 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestInstantiate_Async)
81 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestInstantiate_Async(
82     uint8_t const * pEntropy)
83 {
84     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestInstantiate_Async);
85 
86     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
87     if (MCUXCLCSS_ISBUSY)
88     {
89         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestInstantiate_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
90     }
91 
92     MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pEntropy);
93 
94     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_INSTANTIATE, CSS_CMD_LITTLE_ENDIAN);
95 
96     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestInstantiate_Async, MCUXCLCSS_STATUS_OK_WAIT);
97 }
98 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestExtract_Async)99 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestExtract_Async)
100 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestExtract_Async(
101     uint8_t * pOutput,
102     size_t outputLength)
103 {
104     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestExtract_Async);
105 
106     MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgTestExtract_Async, (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MIN_SIZE > outputLength) ||
107                                                                              (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MAX_SIZE < outputLength) ||
108                                                                              (0U != outputLength % 4U));
109 
110     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
111     if (MCUXCLCSS_ISBUSY)
112     {
113         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestExtract_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
114     }
115 
116     MCUXCLCSS_SETCSSOUTPUT(pOutput, outputLength);
117 
118     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_EXTRACT, CSS_CMD_LITTLE_ENDIAN);
119 
120     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestExtract_Async, MCUXCLCSS_STATUS_OK_WAIT);
121 }
122 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesEcb_Async)123 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesEcb_Async)
124 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestAesEcb_Async(
125     uint8_t const * pDataKey,
126     uint8_t * pOutput)
127 {
128     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestAesEcb_Async);
129 
130     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
131     if (MCUXCLCSS_ISBUSY)
132     {
133         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesEcb_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
134     }
135 
136     MCUXCLCSS_SETCSSINPUT1_FIXEDSIZE(pDataKey);
137     MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
138 
139     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_AES_ECB, CSS_CMD_LITTLE_ENDIAN);
140 
141     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesEcb_Async, MCUXCLCSS_STATUS_OK_WAIT);
142 }
143 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesCtr_Async)144 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesCtr_Async)
145 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestAesCtr_Async(
146     uint8_t const * pData,
147     size_t dataLength,
148     uint8_t const * pIvKey,
149     uint8_t * pOutput)
150 {
151     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestAesCtr_Async);
152 
153     MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgTestAesCtr_Async, (0U != (dataLength % 16U)) || (0U == dataLength));
154 
155     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
156     if (MCUXCLCSS_ISBUSY)
157     {
158         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesCtr_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
159     }
160 
161     MCUXCLCSS_SETCSSINPUT0(pData, dataLength);
162     MCUXCLCSS_SETCSSINPUT1_FIXEDSIZE(pIvKey);
163     MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
164 
165     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_AES_CTR, CSS_CMD_LITTLE_ENDIAN);
166 
167     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesCtr_Async, MCUXCLCSS_STATUS_OK_WAIT);
168 }
169 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigLoad_Async)170 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigLoad_Async)
171 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_Dtrng_ConfigLoad_Async(
172     uint8_t const * pInput)
173 {
174     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_Dtrng_ConfigLoad_Async);
175 
176     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
177     if (MCUXCLCSS_ISBUSY)
178     {
179         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigLoad_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
180     }
181 
182     MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pInput);
183     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DTRNG_CFG_LOAD, 0U, CSS_CMD_LITTLE_ENDIAN);
184 
185     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigLoad_Async, MCUXCLCSS_STATUS_OK_WAIT);
186 }
187 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async)188 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async)
189 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async(
190     uint8_t const * pInput,
191     uint8_t * pOutput)
192 {
193     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async);
194 
195     /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
196     if (MCUXCLCSS_ISBUSY)
197     {
198         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
199     }
200 
201     MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pInput);
202     MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
203     MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DTRNG_EVAL, 0U, CSS_CMD_LITTLE_ENDIAN);
204 
205     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async, MCUXCLCSS_STATUS_OK_WAIT);
206 }
207 
208 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandomWord)209 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandomWord)
210 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Prng_GetRandomWord(
211     uint32_t * pWord)
212 {
213     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Prng_GetRandomWord);
214 
215     *pWord = css_getPRNGWord();
216 
217     /* check if enough entropy is available */
218     if (1U == IP_CSS->CSS_ERR_STATUS_b.PRNG_ERR)
219     {
220 		/* clear CSS error flags */
221 		(void) mcuxClCss_ResetErrorFlags();  /* always returns MCUXCLCSS_STATUS_OK. */
222 
223         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandomWord, MCUXCLCSS_STATUS_HW_PRNG);
224     }
225 
226     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandomWord, MCUXCLCSS_STATUS_OK);
227 }
228 
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandom)229 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandom)
230 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Prng_GetRandom(
231     uint8_t * pOutput,
232     size_t outputLength)
233 {
234     MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Prng_GetRandom);
235 
236     uint8_t * bytePtr = pOutput;
237     uint8_t * const pOutputEnd = pOutput + outputLength;
238 
239     /* Fetch one word of PRNG and fill the leading "not word aligned" bytes */
240     if (0u != ((uint32_t) bytePtr & 0x03u))
241     {
242         uint32_t randomWord = css_getPRNGWord();
243         do
244         {
245             *bytePtr = (uint8_t) (randomWord & 0xFFu);
246             bytePtr += 1u;
247             randomWord >>= 8u;
248         } while ((0u != ((uint32_t) bytePtr & 0x03u)) && (pOutputEnd > bytePtr));
249     }
250 
251     /* Fill the specified buffer wordwise */
252     uint8_t * const pOutputWordEnd = (uint8_t*) ((uint32_t) pOutputEnd & 0xFFFFFFFCu);
253     while (pOutputWordEnd > bytePtr)
254     {
255         mcuxClMemory_StoreLittleEndian32(bytePtr, css_getPRNGWord());
256         bytePtr += 4;
257     }
258 
259     /* Fetch one word of PRNG and fill the remaining "less than one word" bytes */
260     if (pOutputEnd > bytePtr)
261     {
262         uint32_t randomWord = css_getPRNGWord();
263         do
264         {
265             *bytePtr = (uint8_t) (randomWord & 0xFFu);
266             bytePtr += 1u;
267             randomWord >>= 8u;
268         } while (pOutputEnd > bytePtr);
269     }
270 
271     /* check if enough entropy is available */
272     if (1U == IP_CSS->CSS_ERR_STATUS_b.PRNG_ERR)
273     {
274 		/* clear CSS error flags */
275 		(void) mcuxClCss_ResetErrorFlags();  /* always returns MCUXCLCSS_STATUS_OK. */
276 
277         MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandom, MCUXCLCSS_STATUS_HW_PRNG);
278     }
279 
280     MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandom, MCUXCLCSS_STATUS_OK);
281 }
282