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