1 /*
2  * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "cc_otp_defs.h"
8 #include "cc_pal_mem.h"
9 #include "dx_crys_kernel.h"
10 #include "prod_hw_defs.h"
11 #include "cc_pal_log.h"
12 #include "prod_util.h"
13 #include "cc_prod_error.h"
14 #include "cmpu_llf_rnd.h"
15 #include "prod_crypto_driver.h"
16 #include "cmpu_derivation.h"
17 #include "mbedtls_cc_mng_int.h"
18 #include "mbedtls_cc_mng.h"
19 
20 
CC_PROD_CalcHuk(uint32_t * pBuffForOtp,uint32_t * pManufactorWord,unsigned long workspaceAddr)21 static uint32_t CC_PROD_CalcHuk(uint32_t *pBuffForOtp,
22                                 uint32_t *pManufactorWord,
23                                 unsigned long workspaceAddr)
24 {
25     uint32_t error = 0;
26     uint32_t  zeroCount = 0;
27     uint8_t   pKey[CC_PROD_AES_Key256Bits_SIZE_IN_BYTES] = { 0 };
28     uint8_t   pIv[CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES] = { 0 };
29     uint32_t *pEntrSrc;
30     uint32_t  sourceSize;
31     uint32_t *pRndWorkBuff;
32 
33     /*Call CC_PROD_LLF_RND_GetTrngSource to get entropy bits and to check entropy size*/
34     pRndWorkBuff = (uint32_t *)workspaceAddr;
35     error = CC_PROD_LLF_RND_GetTrngSource((uint32_t **)&pEntrSrc, &sourceSize, pRndWorkBuff);
36     if (error != CC_OK) {
37         CC_PAL_LOG_ERR("failed CC_PROD_LLF_RND_GetTrngSource, error is 0x%X\n", error);
38         return error;
39     }
40     error = CC_PROD_Derivation_Instantiate(pEntrSrc,
41                                            sourceSize,
42                                            pKey,
43                                            pIv);
44     if (error != CC_OK) {
45         CC_PAL_LOG_ERR("failed to CC_PROD_Derivation_Instantiate, error 0x%x\n", error);
46         return error;
47     }
48     error = CC_PROD_Derivation_Generate(pKey,
49                                         pIv,
50                                         pBuffForOtp,
51                                         CC_OTP_HUK_SIZE_IN_WORDS * sizeof(uint32_t));
52     if (error != CC_OK) {
53         CC_PAL_LOG_ERR("failed to CC_PROD_Derivation_Generate, error 0x%x\n", error);
54         return error;
55     }
56 
57     error = CC_PROD_LLF_RND_VerifyGeneration((uint8_t *)pBuffForOtp);
58     if (error != CC_OK) {
59         CC_PAL_LOG_ERR("failed to CC_PROD_LLF_RND_VerifyGeneration, error 0x%x\n", error);
60         return error;
61     }
62 
63     /*Count number of zero bits in HUK OTP fileds*/
64     error  = CC_PROD_GetZeroCount(pBuffForOtp, CC_OTP_HUK_SIZE_IN_WORDS, &zeroCount);
65     if (error != CC_OK) {
66         CC_PAL_LOG_ERR("Invalid Huk zero count\n");
67         return error;
68     }
69 
70     SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, HUK_ZERO_BITS, zeroCount);
71     return CC_OK;
72 }
73 
CC_PROD_HandleHbk0(CCCmpuData_t * pCmpuData,uint32_t * pHbk0BuffForOtp,uint32_t * pDcuLockBuffForOtp,uint32_t * pSwVerBuffForOtp,uint32_t * pManufactorWord)74 static uint32_t CC_PROD_HandleHbk0(CCCmpuData_t *pCmpuData,
75                                    uint32_t *pHbk0BuffForOtp,
76                                    uint32_t *pDcuLockBuffForOtp,
77                                    uint32_t *pSwVerBuffForOtp,
78                                    uint32_t *pManufactorWord)
79 {
80     uint32_t error = 0;
81     uint32_t  zeroCount = 0;
82     uint32_t  i = 0;
83     uint32_t icvOwnership = 0;
84     switch (pCmpuData->uniqueDataType){
85     case CMPU_UNIQUE_IS_USER_DATA:
86         /* If HBK not in use set the bit in manufactor flag */
87         SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, HBK0_NOT_IN_USE, 1);
88         break;
89 
90     case CMPU_UNIQUE_IS_HBK0:
91         /* Calculate HBK0 zeros */
92         CC_PalMemCopy(pHbk0BuffForOtp, pCmpuData->uniqueBuff.hbk0, CC_OTP_HBK0_SIZE_IN_WORDS * CC_32BIT_WORD_SIZE);
93         error = CC_PROD_GetZeroCount(pHbk0BuffForOtp, PROD_KEY_TMP_CONTEXT_WORD_SIZE, &zeroCount);
94         if (error != CC_OK) {
95             CC_PAL_LOG_ERR("Invalid Huk zero count\n");
96             return error;
97         }
98 
99         /* Keep only ICV bit in DCU default locking */
100         for (i = 0; i < CC_OTP_DCU_SIZE_IN_WORDS; i++) {
101             icvOwnership = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, AO_ICV_DCU_RESTRICTION_MASK0) + (i * CC_32BIT_WORD_SIZE));
102             pDcuLockBuffForOtp[i] = pCmpuData->icvDcuDefaultLock[i] & icvOwnership;
103         }
104 
105         /* set ICV minimum SW version */
106         error = CC_PROD_BitListFromNum(pSwVerBuffForOtp, CC_OTP_HBK0_MIN_VERSION_SIZE_IN_WORDS, pCmpuData->icvMinVersion);
107         if (error != CC_OK) {
108             CC_PAL_LOG_ERR("Failed to get bit list from number\n");
109             return error;
110         }
111         break;
112 
113     default:
114         CC_PAL_LOG_ERR("Invalid unique data type \n");
115         return CC_PROD_INVALID_PARAM_ERR;
116     }
117 
118     SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, HBK0_ZERO_BITS, zeroCount);
119     return CC_OK;
120 }
121 
122 
CC_PROD_HandleKpicv(CCCmpuData_t * pCmpuData,uint32_t * pBuffForOtp,uint32_t * pManufactorWord,unsigned long workspaceAddr,uint32_t workspaceSize)123 static uint32_t CC_PROD_HandleKpicv(CCCmpuData_t *pCmpuData,
124                                     uint32_t *pBuffForOtp,
125                                     uint32_t *pManufactorWord,
126                                     unsigned long workspaceAddr,
127                                     uint32_t     workspaceSize)
128 {
129     uint32_t error = 0;
130     uint32_t  zeroCount = 0;
131 
132     switch (pCmpuData->kpicvDataType) {
133     case  ASSET_NO_KEY:
134         SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, KPICV_NOT_IN_USE, 1);
135         goto end_kpicv;
136     case  ASSET_PKG_KEY:
137         error = CC_PROD_PkgVerify((CCProdAssetPkg_t *)&pCmpuData->kpicv.pkgAsset,
138                                   (const uint8_t *)PROD_ICV_PROV_CONTEXT, PROD_KPROV_CONTEXT_SIZE,
139                                   (const uint8_t *)PROD_ICV_KEY_TMP_LABEL, PROD_KEY_TMP_LABEL_SIZE,
140                                   pCmpuData->uniqueBuff.hbk0, CC_OTP_HBK0_SIZE_IN_WORDS * CC_32BIT_WORD_SIZE,
141                                   (uint8_t *  )pBuffForOtp,
142                                   workspaceAddr,
143                                   workspaceSize);
144         if (error != CC_OK) {
145             CC_PAL_LOG_ERR("failed to CC_PROD_PkgVerify fro Kpicv\n");
146             return error;
147         }
148         break;
149     case ASSET_PLAIN_KEY:
150         CC_PalMemCopy(pBuffForOtp, pCmpuData->kpicv.plainAsset, PROD_ASSET_SIZE);
151         break;
152     default:
153         CC_PAL_LOG_ERR("Inavlid key type for  Kpicv\n");
154         return CC_PROD_INVALID_PARAM_ERR;
155     }
156     error = CC_PROD_GetZeroCount(pBuffForOtp, PROD_KEY_TMP_CONTEXT_WORD_SIZE, &zeroCount);
157     if (error != CC_OK) {
158         CC_PAL_LOG_ERR("Invalid zero count for Kpicv\n");
159         return error;
160     }
161 end_kpicv:
162     SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, KPICV_ZERO_BITS, zeroCount);
163     return CC_OK;
164 }
165 
166 
CC_PROD_HandleKceicv(CCCmpuData_t * pCmpuData,uint32_t * pBuffForOtp,uint32_t * pManufactorWord,unsigned long workspaceAddr,uint32_t workspaceSize)167 static uint32_t CC_PROD_HandleKceicv(CCCmpuData_t *pCmpuData,
168                                      uint32_t *pBuffForOtp,
169                                      uint32_t *pManufactorWord,
170                                      unsigned long workspaceAddr,
171                                      uint32_t     workspaceSize)
172 {
173     uint32_t error = 0;
174     uint32_t  zeroCount = 0;
175 
176     switch (pCmpuData->kceicvDataType) {
177     case  ASSET_NO_KEY:
178         SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, KCEICV_NOT_IN_USE, 1);
179         goto end_kceicv;
180     case  ASSET_PKG_KEY:
181         error = CC_PROD_PkgVerify((CCProdAssetPkg_t *)&pCmpuData->kceicv.pkgAsset,
182                                   (const uint8_t *)PROD_ICV_ENC_CONTEXT, PROD_KPROV_CONTEXT_SIZE,
183                                   (const uint8_t *)PROD_ICV_KEY_TMP_LABEL, PROD_KEY_TMP_LABEL_SIZE,
184                                   pCmpuData->uniqueBuff.hbk0, CC_OTP_HBK0_SIZE_IN_WORDS * CC_32BIT_WORD_SIZE,
185                                   (uint8_t *  )pBuffForOtp,
186                                   workspaceAddr,
187                                   workspaceSize);
188         if (error != CC_OK) {
189             CC_PAL_LOG_ERR("failed to CC_PROD_PkgVerify fro Kceicv\n");
190             return error;
191         }
192         break;
193     case ASSET_PLAIN_KEY:
194         CC_PalMemCopy(pBuffForOtp, pCmpuData->kceicv.plainAsset, PROD_ASSET_SIZE);
195         break;
196     default:
197         CC_PAL_LOG_ERR("Invalid key type for Kceicv\n");
198         return CC_PROD_INVALID_PARAM_ERR;
199     }
200 
201     error = CC_PROD_GetZeroCount(pBuffForOtp, PROD_KEY_TMP_CONTEXT_WORD_SIZE, &zeroCount);
202     if (error != CC_OK) {
203         CC_PAL_LOG_ERR("Invalid zerocount for Kceicv\n");
204         return error;
205     }
206 
207 end_kceicv:
208     SET_OTP_MANUFACTURE_FLAG(*pManufactorWord, KCEICV_ZERO_BITS, zeroCount);
209     return CC_OK;
210 }
211 
212 
213 
CCProd_Cmpu(unsigned long ccHwRegBaseAddr,CCCmpuData_t * pCmpuData,unsigned long workspaceBaseAddr,uint32_t workspaceSize)214 CCError_t CCProd_Cmpu( unsigned long  ccHwRegBaseAddr,
215                        CCCmpuData_t   *pCmpuData,
216                        unsigned long  workspaceBaseAddr,
217                        uint32_t       workspaceSize)
218 {
219     uint32_t error = 0;
220     uint32_t lcs = 0;
221     uint32_t manufactorWord = 0;
222     uint32_t hukBuffForOtp[CC_OTP_HUK_SIZE_IN_WORDS] = { 0 };
223     uint32_t hbk0BuffForOtp[CC_OTP_HBK0_SIZE_IN_WORDS] = { 0 };
224     uint32_t kpicvBuffForOtp[CC_OTP_KPICV_SIZE_IN_WORDS] = { 0 };
225     uint32_t kceicvBuffForOtp[CC_OTP_KCEICV_SIZE_IN_WORDS] = { 0 };
226     uint32_t icvLockBitsBuffForOtp[CC_OTP_DCU_SIZE_IN_WORDS] = { 0 };
227     uint32_t   icvMinSwVersion[CC_OTP_HBK0_MIN_VERSION_SIZE_IN_WORDS] = { 0 };
228 
229     if (sizeof(CCProdAssetPkg_t) != PROD_ASSET_PKG_SIZE) {
230         CC_PAL_LOG_ERR("invalid Pkg size\n");
231         return CC_PROD_INVALID_PARAM_ERR;
232     }
233     if ((pCmpuData == NULL) ||
234             (workspaceBaseAddr == 0) ||  //can not be zero because it is cast to a pointer later
235             (workspaceBaseAddr % CC_32BIT_WORD_SIZE) ||   // workspace address must be word aligned
236             (workspaceSize < CMPU_WORKSPACE_MINIMUM_SIZE) ) {
237         CC_PAL_LOG_ERR("invalid params\n");
238         return CC_PROD_INVALID_PARAM_ERR;
239     }
240 
241     gCcRegBase = ccHwRegBaseAddr;
242 
243     error = CCProd_Init();
244     if (error != CC_OK) {
245         CC_PAL_LOG_ERR("Failed to CCProd_Init 0x%x\n", error);
246         goto cmpuEnd;
247     }
248 
249     /* Check LCS - CM only */
250     error = mbedtls_mng_lcsGet(&lcs);
251     if (error != CC_OK) {
252         CC_PAL_LOG_ERR("Failed to get LCS 0x%x \n", error);
253         goto cmpuEnd;
254     }
255 
256     /* Verify LCS is CM */
257     if (lcs != CC_MNG_LCS_CM) {
258         CC_PAL_LOG_ERR("LCS is %d not valid\n", lcs);
259         error = CC_PROD_ILLEGAL_LCS_ERR;
260         goto cmpuEnd;
261     }
262 
263     /* Genertae HUK  */
264     error = CC_PROD_CalcHuk(hukBuffForOtp, &manufactorWord, workspaceBaseAddr);
265     if (error != CC_OK) {
266         CC_PAL_LOG_ERR("failed to CC_PROD_CalcHuk 0x%x \n", error);
267         goto cmpuEnd;
268     }
269 
270     /* Set HBK0 if exists, and calculate its zero count. or set HBK0 not in use
271            Handle HBK0  dependencies: DCU lock bits and ICV minimum version */
272     error = CC_PROD_HandleHbk0(pCmpuData, hbk0BuffForOtp, icvLockBitsBuffForOtp, icvMinSwVersion, &manufactorWord);
273     if (error != CC_OK) {
274         CC_PAL_LOG_ERR("failed to CC_PROD_HandleHbk0 0x%x \n", error);
275         goto cmpuEnd;
276     }
277 
278     /* Handle Kpicv, or set Kpicv not in use */
279     error = CC_PROD_HandleKpicv(pCmpuData, kpicvBuffForOtp, &manufactorWord, workspaceBaseAddr, workspaceSize);
280     if (error != CC_OK) {
281         CC_PAL_LOG_ERR("failed to CC_PROD_HandleKpicv 0x%x \n", error);
282         goto cmpuEnd;
283     }
284 
285 
286     /* Handle Kceicv, , or set Kceicv not in use */
287     error = CC_PROD_HandleKceicv(pCmpuData, kceicvBuffForOtp, &manufactorWord, workspaceBaseAddr, workspaceSize);
288     if (error != CC_OK) {
289         CC_PAL_LOG_ERR("failed to CC_PROD_HandleKceicv 0x%x \n", error);
290         goto cmpuEnd;
291     }
292 
293     /* First, Burn Manufactor flag, including not in use flags set by ahndle functions above  */
294     CC_PROD_OTP_WRITE_VERIFY_WORD(CC_OTP_MANUFACTURE_FLAG_OFFSET, manufactorWord, error);
295     if (error != CC_OK) {
296         CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
297         goto cmpuEnd;
298     }
299 
300     /* Burn Huk */
301     CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_HUK_OFFSET, hukBuffForOtp, CC_OTP_HUK_SIZE_IN_WORDS, error);
302     if (error != CC_OK) {
303         CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
304         goto cmpuEnd;
305     }
306 
307     /* Burn HBK0 and its dependencies: DCU lock bits and SW version */
308     if (pCmpuData->uniqueDataType == CMPU_UNIQUE_IS_HBK0) {
309         /* HBK0 */
310         CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_HBK0_OFFSET, hbk0BuffForOtp, CC_OTP_HBK0_SIZE_IN_WORDS, error);
311         if (error != CC_OK) {
312             CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
313             goto cmpuEnd;
314         }
315         /* DCU lock bits */
316         CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_DCU_OFFSET, icvLockBitsBuffForOtp, CC_OTP_DCU_SIZE_IN_WORDS, error);
317         if (error != CC_OK) {
318             CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
319             goto cmpuEnd;
320         }
321         /* SW version */
322         CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_HBK0_MIN_VERSION_OFFSET, icvMinSwVersion, CC_OTP_HBK0_MIN_VERSION_SIZE_IN_WORDS, error);
323         if (error != CC_OK) {
324             CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
325             goto cmpuEnd;
326         }
327     }
328     /* Burn Kpicv */
329     if (pCmpuData->kpicvDataType  != ASSET_NO_KEY)  {
330         CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_KPICV_OFFSET, kpicvBuffForOtp, CC_OTP_KPICV_SIZE_IN_WORDS, error);
331         if (error != CC_OK) {
332             CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
333             goto cmpuEnd;
334         }
335     }
336     /* Burn Kceicv*/
337     if (pCmpuData->kceicvDataType  != ASSET_NO_KEY)  {
338         CC_PROD_OTP_WRITE_VERIFY_WORD_BUFF(CC_OTP_KCEICV_OFFSET, kceicvBuffForOtp, CC_OTP_KCEICV_SIZE_IN_WORDS, error);
339         if (error != CC_OK) {
340             CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
341             goto cmpuEnd;
342         }
343     }
344     /* Burn icv configuration word */
345     CC_PROD_OTP_WRITE_VERIFY_WORD(CC_OTP_ICV_GENERAL_PURPOSE_FLAG_OFFSET,
346                                   pCmpuData->icvConfigWord,
347                                   error);
348     if (error != CC_OK) {
349         CC_PAL_LOG_ERR("Failed to verify OTP write 0x%x \n", error);
350         goto cmpuEnd;
351     }
352 
353 cmpuEnd:
354     CC_PalMemSetZero((uint8_t *)workspaceBaseAddr, workspaceSize);
355     if (error != CC_OK) {
356         CC_PAL_LOG_ERR("CMPU failed, error = 0x%x \n", error);
357     }
358     CCPROD_Fini();
359     return error;
360 }
361 
362 
363 
364