1 /*
2 * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include "secureboot_basetypes.h"
7 #include "util_asn1_parser.h"
8 #include "util_x509_parser.h"
9 #include "sb_x509_error.h"
10 #include "sb_x509_cert_parser.h"
11 #include "cc3x_sb_x509_ext_parser.h"
12 #include "bootimagesverifier_error.h"
13 #include "cc_pal_x509_defs.h"
14 #include "bsv_error.h"
15 #include "cc_bitops.h"
16 #include "cc_pal_log.h"
17 #include "secdebug_defs.h"
18 #include "cc_pka_hw_plat_defs.h"
19 #include "common_cert_parser.h"
20 #include "secureboot_stage_defs.h"
21
22
23 #define SIZE_OF_CERT_ASN1_HEADER 4 // 0x30,0x82, MSB size, LSB size - not like CCSbCertAsn1Data_t, since we have 2 bytes of certificate size
24
25 /**
26 @brief This function verifies the secure debug package size and returns the
27 pointer to each of the certificates within the package.
28 from the ASN.1 first package we read the first certificate size.
29 We jump to the following certificate and read its size from the ASN.1 header.
30 If the sum of both certificates smaller than the certificate package size,
31 we assume we have key certificate as well. And set the certificate pointers
32 according to the ASN.1 header sizes of each certificate.
33 In any case we need to compare each certificate size and the certificate package
34 total size with the maximum possible value of the certificate sizes.
35 */
CCCertSecDbgParse(uint32_t * pDebugCertPkg,uint32_t certPkgSize,BufferInfo32_t * pKeyCert,BufferInfo32_t * pEnablerCert,BufferInfo32_t * pDeveloperCert)36 CCError_t CCCertSecDbgParse(uint32_t *pDebugCertPkg,
37 uint32_t certPkgSize,
38 BufferInfo32_t *pKeyCert, // out
39 BufferInfo32_t *pEnablerCert, // out
40 BufferInfo32_t *pDeveloperCert) // out
41 {
42
43 uint32_t rc = 0;
44 CCSbCertAsn1Data_t asn1DataCert1;
45 CCSbCertAsn1Data_t asn1DataCert2;
46 uint32_t cert2WordOffset;
47 CCSbCertAsn1Data_t asn1DataCert3;
48 uint32_t cert3WordOffset;
49 uint32_t numOfCert = 0;
50 uint32_t *pCertPkg = pDebugCertPkg;
51 uint32_t *pCertFirst;
52 uint32_t *pCertSecond;
53 uint32_t *pCertThird;
54 unsigned long endAddr = (unsigned long)pDebugCertPkg + certPkgSize;
55
56 /* certificate offsets within package must be word aligned */
57 // Get the first certificate size
58 pCertFirst = pCertPkg;
59 rc = UTIL_Asn1ReadItemVerifyTagFW((uint8_t **)&pCertPkg, &asn1DataCert1, CC_X509_CERT_SEQ_TAG_ID, (unsigned long)pCertPkg, endAddr);
60 if (rc != CC_OK) {
61 CC_PAL_LOG_ERR("Failed to UTIL_Asn1ReadItemVerifyTagFW 0x%x for cert1\n", rc);
62 goto end_with_error;
63 }
64
65 /* Make sure no wrap around */
66 if ((asn1DataCert1.itemSize + SIZE_OF_CERT_ASN1_HEADER) < asn1DataCert1.itemSize) {
67 CC_PAL_LOG_ERR("illegal value %d\n", asn1DataCert1.itemSize);
68 goto end_with_error;
69 }
70
71 /* Some sanity checks for certificate size*/
72 if (((asn1DataCert1.itemSize + SIZE_OF_CERT_ASN1_HEADER) > certPkgSize) || ((asn1DataCert1.itemSize + SIZE_OF_CERT_ASN1_HEADER) > CC_SB_MAX_ENABLER_CERT_SIZE_IN_BYTES)) {
73 CC_PAL_LOG_ERR("asn1Data.itemSize(0x%x) > certPkgSize(0x%x)\n", asn1DataCert1.itemSize, certPkgSize);
74 goto end_with_error;
75 }
76 numOfCert++;
77
78 /* Get the second certificate size */
79 cert2WordOffset = CALC_32BIT_WORDS_FROM_BYTES(asn1DataCert1.itemSize);
80 if ((cert2WordOffset * CC_32BIT_WORD_SIZE + SIZE_OF_CERT_ASN1_HEADER) > certPkgSize) {
81 CC_PAL_LOG_ERR("cert2WordOffset(0x%x) > certPkgSize(0x%x)\n", cert2WordOffset * CC_32BIT_WORD_SIZE, certPkgSize);
82 goto end_with_error;
83 }
84 pCertPkg += cert2WordOffset;
85 pCertSecond = pCertPkg;
86 rc = UTIL_Asn1ReadItemVerifyTagFW((uint8_t **)&pCertPkg, &asn1DataCert2, CC_X509_CERT_SEQ_TAG_ID, (unsigned long)pCertPkg, endAddr);
87 if (rc != CC_OK) {
88 CC_PAL_LOG_ERR("Failed to UTIL_Asn1ReadItemVerifyTagFW 0x%x for cert2\n", rc);
89 goto end_with_error;
90 }
91
92 /* Verify no wrap around. */
93 if ((asn1DataCert2.itemSize + SIZE_OF_CERT_ASN1_HEADER) < asn1DataCert2.itemSize) {
94 CC_PAL_LOG_ERR("illegal value %d\n", asn1DataCert1.itemSize);
95 goto end_with_error;
96 }
97 if ((asn1DataCert2.itemSize + SIZE_OF_CERT_ASN1_HEADER) > (certPkgSize - (cert2WordOffset * CC_32BIT_WORD_SIZE)) ||
98 ((asn1DataCert2.itemSize + SIZE_OF_CERT_ASN1_HEADER) > CC_SB_MAX_ENABLER_CERT_SIZE_IN_BYTES)) { /* enabler certificate is the biggest certificate */
99 CC_PAL_LOG_ERR("asn1DataCert2.itemSize(0x%x) > (certPkgSize(0x%x)-cert2WordOffset(0x%x))\n",
100 asn1DataCert2.itemSize, certPkgSize, cert2WordOffset);
101 goto end_with_error;
102 }
103 numOfCert++;
104
105 // Get the third certificate size - if the offset is outside of boundaries return (there are only 2 certificates).
106 cert3WordOffset = CALC_32BIT_WORDS_FROM_BYTES(asn1DataCert2.itemSize) + cert2WordOffset;
107 if (((cert3WordOffset * CC_32BIT_WORD_SIZE) + 2 * SIZE_OF_CERT_ASN1_HEADER) >= certPkgSize) { // meaning only 2 certificates in chain
108 goto end;
109 }
110 pCertPkg += (cert3WordOffset - cert2WordOffset);
111 pCertThird = pCertPkg;
112 rc = UTIL_Asn1ReadItemVerifyTagFW((uint8_t **)&pCertPkg, &asn1DataCert3, CC_X509_CERT_SEQ_TAG_ID, (unsigned long)pCertPkg, endAddr);
113 if (rc != CC_OK) {
114 CC_PAL_LOG_ERR("Failed to UTIL_Asn1ReadItemVerifyTagFW 0x%x for cert3\n", rc);
115 goto end_with_error;
116 }
117
118 if ((asn1DataCert3.itemSize + SIZE_OF_CERT_ASN1_HEADER) < asn1DataCert3.itemSize) {
119 CC_PAL_LOG_ERR("illegal value %d\n", asn1DataCert3.itemSize);
120 goto end_with_error;
121 }
122 if ((asn1DataCert3.itemSize + SIZE_OF_CERT_ASN1_HEADER) > (certPkgSize - (cert3WordOffset * CC_32BIT_WORD_SIZE)) ||
123 ((asn1DataCert3.itemSize + SIZE_OF_CERT_ASN1_HEADER) > CC_SB_MAX_ENABLER_CERT_SIZE_IN_BYTES)) {
124 CC_PAL_LOG_ERR("asn1DataCert3.itemSize(0x%x) > (certPkgSize(0x%x)-cert3WordOffset(0x%x))\n",
125 asn1DataCert3.itemSize, certPkgSize, cert3WordOffset * CC_32BIT_WORD_SIZE);
126 goto end_with_error;
127 }
128 numOfCert++;
129
130 end:
131 if (numOfCert == 2) {
132 pKeyCert->bufferSize = 0;
133 pKeyCert->pBuffer = NULL;
134 pEnablerCert->bufferSize = asn1DataCert1.itemSize;
135 pEnablerCert->pBuffer = pCertFirst;
136 pDeveloperCert->bufferSize = asn1DataCert2.itemSize;
137 pDeveloperCert->pBuffer = pCertSecond;
138 } else if (numOfCert == 3) {
139 pKeyCert->bufferSize = asn1DataCert1.itemSize;
140 pKeyCert->pBuffer = pCertFirst;
141 pEnablerCert->bufferSize = asn1DataCert2.itemSize;
142 pEnablerCert->pBuffer = pCertSecond;
143 pDeveloperCert->bufferSize = asn1DataCert3.itemSize;
144 pDeveloperCert->pBuffer = pCertThird;
145 }
146 return CC_OK;
147
148 end_with_error:
149 pKeyCert->bufferSize = 0;
150 pKeyCert->pBuffer = NULL;
151 pEnablerCert->bufferSize = 0;
152 pEnablerCert->pBuffer = NULL;
153 pDeveloperCert->bufferSize = 0;
154 pDeveloperCert->pBuffer = NULL;
155
156 return CC_SB_X509_CERT_PARSE_ILLEGAL_VAL;
157
158 }
159
160
161 /**
162 @brief This function load sizeof(CCSbCertAsn1Data_t ) from flash and get the
163 certificate size from it. Make sure size is within range
164 (smaller than workspace size not including the required space for N, Np and signature).
165 read the certificate according to size from header and copy the certificate content from Flash to RAM.
166 */
CCCertLoadCertificate(CCSbFlashReadFunc flashRead_func,void * userContext,CCAddr_t certAddress,uint32_t * pCert,uint32_t * pCertBufferWordSize)167 uint32_t CCCertLoadCertificate(CCSbFlashReadFunc flashRead_func,
168 void *userContext,
169 CCAddr_t certAddress,
170 uint32_t *pCert,
171 uint32_t *pCertBufferWordSize)
172 {
173 uint32_t rc = 0;
174 CCSbCertAsn1Data_t asn1DataCert1;
175 uint8_t *plCert = (uint8_t *)pCert;
176 uint32_t certSizeFullWords;
177
178 /* Verify that the certificate buffer size is big enough to contain the header */
179 if (*pCertBufferWordSize < (SIZE_OF_CERT_ASN1_HEADER / CC_32BIT_WORD_SIZE)) {
180 CC_PAL_LOG_ERR("certificate buff size too small to contain certificate header\n");
181 return CC_BOOT_IMG_VERIFIER_WORKSPACE_SIZE_TOO_SMALL;
182 }
183
184 /* Read the certificate header from the Flash */
185 rc = flashRead_func(certAddress,
186 plCert,
187 SIZE_OF_CERT_ASN1_HEADER,
188 userContext);
189 if (rc != CC_OK) {
190 CC_PAL_LOG_ERR("failed flashRead_func for certificate header\n");
191 return rc;
192 }
193
194 rc = UTIL_Asn1ReadItemVerifyTagFW((uint8_t **)&plCert,
195 &asn1DataCert1,
196 CC_X509_CERT_SEQ_TAG_ID,
197 (unsigned long)plCert,
198 (unsigned long)plCert + SIZE_OF_CERT_ASN1_HEADER);
199 if (rc != CC_OK) {
200 CC_PAL_LOG_ERR("Failed to UTIL_Asn1ReadItemVerifyTagFW 0x%x for cert header\n", rc);
201 return rc;
202 }
203
204 certSizeFullWords = ALIGN_TO_4BYTES(asn1DataCert1.itemSize);
205
206 /* Verify no wrap around */
207 if ((*pCertBufferWordSize) * CC_32BIT_WORD_SIZE - SIZE_OF_CERT_ASN1_HEADER > (*pCertBufferWordSize) * CC_32BIT_WORD_SIZE) {
208 CC_PAL_LOG_ERR("Certificate size too big\n");
209 return CC_BOOT_IMG_VERIFIER_INV_INPUT_PARAM;
210 }
211 /* Make sure certificate size is within range */
212 if (certSizeFullWords > ((*pCertBufferWordSize) * CC_32BIT_WORD_SIZE - SIZE_OF_CERT_ASN1_HEADER)) {
213 CC_PAL_LOG_ERR("Certificate size too big\n");
214 return CC_BOOT_IMG_VERIFIER_INV_INPUT_PARAM;
215 }
216
217 /* according to the header read the additional certificate buffer -
218 * not including the non-signed part in case of content certificate */
219 rc = flashRead_func(certAddress + SIZE_OF_CERT_ASN1_HEADER,
220 (uint8_t *)plCert,
221 asn1DataCert1.itemSize,
222 userContext);
223 if (rc != CC_OK) {
224 CC_PAL_LOG_ERR("failed flashRead_func for certificate\n");
225 return rc;
226 }
227
228 *pCertBufferWordSize = ((certSizeFullWords + SIZE_OF_CERT_ASN1_HEADER) / CC_32BIT_WORD_SIZE);
229
230 return CC_OK;
231
232 }
233
234
235 /**
236 @brief This function
237 call SB_X509_VerifyCertTbsHeader() to verify the X509 header and get the user Data and public key.
238 Copy the public key into workspace
239 Call SB_X509_ParseCertExtensions() to get pointers for:
240 Proprietary header pointer
241 Copy Np into workspace following N
242 Proprietary Certificate body pointer
243 Call UTIL_X509GetSignature(), and copy the signature into workspace, after Np.
244 */
CCCertFieldsParse(BufferInfo32_t * pCertInfo,BufferInfo32_t * pWorkspaceInfo,CertFieldsInfo_t * pCertFields,uint32_t ** ppCertStartSign,uint32_t * pCertSignedSize,BufferInfo32_t * pX509HeaderInfo)245 uint32_t CCCertFieldsParse(BufferInfo32_t *pCertInfo,
246 BufferInfo32_t *pWorkspaceInfo,
247 CertFieldsInfo_t *pCertFields,
248 uint32_t **ppCertStartSign,
249 uint32_t *pCertSignedSize,
250 BufferInfo32_t *pX509HeaderInfo)
251 {
252 uint32_t rc = 0;
253 uint32_t certSignedSize = 0;
254 uint32_t certStartOffest;
255 CCSbCertHeader_t *lpCertHeader;
256 uint8_t *lpNp;
257 CCSbSignature_t *lpSignature;
258 unsigned long startAddr = (unsigned long)pCertInfo->pBuffer;
259 unsigned long endAddr = (unsigned long)pCertInfo->pBuffer + pCertInfo->bufferSize + sizeof(CCSbCertAsn1Data_t);
260 CCX509CertHeaderInfo_t *pX509UserData = NULL;
261 uint8_t *pX509Cert = (uint8_t *)pCertInfo->pBuffer;
262 workspaceInt_t *lpWorkspaceInt;
263
264 if ((pWorkspaceInfo == NULL) ||
265 (pWorkspaceInfo->pBuffer == NULL) ||
266 (pWorkspaceInfo->bufferSize < sizeof(workspaceInt_t))) {
267 CC_PAL_LOG_ERR("workspace and or sizes illegal\n");
268 return CC_BSV_ILLEGAL_INPUT_PARAM_ERR;
269 }
270
271 if (startAddr > endAddr) { /* Verify no overlap */
272 CC_PAL_LOG_ERR("buffer overlap detected \n");
273 return CC_BSV_ILLEGAL_INPUT_PARAM_ERR;
274 }
275 lpWorkspaceInt = (workspaceInt_t *)(pWorkspaceInfo->pBuffer);
276
277 if (pX509HeaderInfo != NULL) {
278 if (((pX509HeaderInfo->pBuffer == NULL) && (pX509HeaderInfo->bufferSize != 0)) ||
279 ((pX509HeaderInfo->pBuffer != NULL) && (pX509HeaderInfo->bufferSize < sizeof(CCX509CertHeaderInfo_t)))) {
280 CC_PAL_LOG_ERR("workspace and or sizes illegal\n");
281 return CC_BSV_ILLEGAL_INPUT_PARAM_ERR;
282 }
283 pX509UserData = (CCX509CertHeaderInfo_t *)pX509HeaderInfo->pBuffer;
284 }
285
286 rc = SB_X509_VerifyCertTbsHeader(&pX509Cert,
287 pCertInfo->bufferSize,
288 &certSignedSize,
289 &certStartOffest,
290 (CCSbNParams_t *)&(lpWorkspaceInt->pubKey),
291 pX509UserData,
292 startAddr,
293 endAddr);
294
295 if ((rc != CC_OK) ||
296 (certSignedSize > pCertInfo->bufferSize - SB_CERT_RSA_KEY_SIZE_IN_BYTES)) {
297 CC_PAL_LOG_ERR("Failed SB_X509_VerifyCertTbsHeader 0x%x\n", rc);
298 goto error;
299 }
300
301 *ppCertStartSign = pCertInfo->pBuffer + 1;
302 *pCertSignedSize = certSignedSize;
303
304 /* Copy the proprietary header from the extension,
305 copy Np from the extension,
306 get the pointer to the certificate main */
307 rc = SB_X509_ParseCertExtensions(&pX509Cert,
308 certSignedSize,
309 &lpCertHeader,
310 &lpNp,
311 (uint8_t **)&pCertFields->pCertBody,
312 &pCertFields->certBodySize,
313 startAddr,
314 endAddr);
315 if ((rc != CC_OK) ||
316 (pCertFields->certBodySize > certSignedSize)) {
317 CC_PAL_LOG_ERR("Failed SB_X509_ParseCertExtensions 0x%x, or bodySize 0x%x too big 0x%x\n", rc, pCertFields->certBodySize, certSignedSize);
318 goto error;
319 }
320
321 UTIL_MemCopy((uint8_t *)&pCertFields->certHeader, (uint8_t *)lpCertHeader, sizeof(CCSbCertHeader_t));
322 UTIL_MemCopy((uint8_t *)&(lpWorkspaceInt->pubKey.Np), lpNp, RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_BYTES);
323
324
325 lpSignature = (CCSbSignature_t *)&(lpWorkspaceInt->signature);
326 rc = UTIL_X509GetSignature(&pX509Cert, lpSignature, startAddr, endAddr);
327 if (rc != CC_OK) {
328 CC_PAL_LOG_ERR("Failed UTIL_X509GetSignature 0x%x\n", rc);
329 goto error;
330 }
331
332 return CC_OK;
333 error:
334 UTIL_MemSet((uint8_t *)pCertFields, 0, sizeof(CertFieldsInfo_t));
335 *pCertSignedSize = 0;
336
337 return CC_SB_X509_CERT_PARSE_ILLEGAL_VAL;
338 }
339
CCCertGetUnsignedDataOffset(uint32_t * pCert,uint32_t * pUnsignedDataOffset)340 uint32_t CCCertGetUnsignedDataOffset(uint32_t *pCert,
341 uint32_t *pUnsignedDataOffset)
342 {
343 CCError_t rc = CC_OK;
344 uint8_t *plCert = (uint8_t *)pCert;
345 CCSbCertAsn1Data_t asn1DataCert1;
346 uint32_t certSizeFullWords;
347
348 if ((pCert == NULL)||(pUnsignedDataOffset == NULL)){
349 return CC_BOOT_IMG_VERIFIER_INV_INPUT_PARAM;
350 }
351
352 rc = UTIL_Asn1ReadItemVerifyTagFW((uint8_t **)&plCert,
353 &asn1DataCert1,
354 CC_X509_CERT_SEQ_TAG_ID,
355 (unsigned long)plCert,
356 (unsigned long)plCert + SIZE_OF_CERT_ASN1_HEADER);
357 if (rc != CC_OK) {
358 CC_PAL_LOG_ERR("Failed to UTIL_Asn1ReadItemVerifyTagFW 0x%x for cert header\n", rc);
359 return rc;
360 }
361
362 certSizeFullWords = ALIGN_TO_4BYTES(asn1DataCert1.itemSize);
363 *pUnsignedDataOffset = ((certSizeFullWords + SIZE_OF_CERT_ASN1_HEADER) / CC_32BIT_WORD_SIZE);
364
365 return CC_OK;
366 }
367
368