]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
CryptoPkg/Library/BaseCryptLib: Update internal functions/variables
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7VerifyCommon.c
CommitLineData
532616bb 1/** @file\r
2 PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This library will have external input - signature (e.g. UEFI Authenticated\r
6 Variable). It may by input in SMM mode.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated\r
11 Variable and will do basic check for data structure.\r
12\r
cc01b26e 13Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
2009f6b4 14SPDX-License-Identifier: BSD-2-Clause-Patent\r
532616bb 15\r
16**/\r
17\r
18#include "InternalCryptLib.h"\r
19\r
20#include <openssl/objects.h>\r
21#include <openssl/x509.h>\r
02ee8d3b 22#include <openssl/x509v3.h>\r
532616bb 23#include <openssl/pkcs7.h>\r
24\r
8f837243 25GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };\r
532616bb 26\r
532616bb 27/**\r
28 Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
29 a new structure to wrap P7Data.\r
30\r
31 Caution: This function may receive untrusted input.\r
32 UEFI Authenticated Variable is external input, so this function will do basic\r
33 check for PKCS#7 data structure.\r
34\r
35 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
36 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
37 @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise\r
38 return FALSE.\r
2ac68e8b 39 @param[out] WrapData If return status of this function is TRUE:\r
532616bb 40 1) when WrapFlag is TRUE, pointer to P7Data.\r
41 2) when WrapFlag is FALSE, pointer to a new ContentInfo\r
42 structure. It's caller's responsibility to free this\r
43 buffer.\r
44 @param[out] WrapDataSize Length of ContentInfo structure in bytes.\r
45\r
46 @retval TRUE The operation is finished successfully.\r
47 @retval FALSE The operation is failed due to lack of resources.\r
48\r
49**/\r
50BOOLEAN\r
51WrapPkcs7Data (\r
52 IN CONST UINT8 *P7Data,\r
53 IN UINTN P7Length,\r
54 OUT BOOLEAN *WrapFlag,\r
55 OUT UINT8 **WrapData,\r
56 OUT UINTN *WrapDataSize\r
57 )\r
58{\r
7c342378
MK
59 BOOLEAN Wrapped;\r
60 UINT8 *SignedData;\r
532616bb 61\r
62 //\r
63 // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
64 //\r
65 Wrapped = FALSE;\r
66 if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {\r
67 if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {\r
68 if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {\r
69 Wrapped = TRUE;\r
70 }\r
71 }\r
72 }\r
73\r
74 if (Wrapped) {\r
7c342378 75 *WrapData = (UINT8 *)P7Data;\r
532616bb 76 *WrapDataSize = P7Length;\r
77 } else {\r
78 //\r
79 // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.\r
80 //\r
81 *WrapDataSize = P7Length + 19;\r
82 *WrapData = malloc (*WrapDataSize);\r
83 if (*WrapData == NULL) {\r
84 *WrapFlag = Wrapped;\r
85 return FALSE;\r
86 }\r
87\r
88 SignedData = *WrapData;\r
89\r
90 //\r
91 // Part1: 0x30, 0x82.\r
92 //\r
93 SignedData[0] = 0x30;\r
94 SignedData[1] = 0x82;\r
95\r
96 //\r
97 // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
98 //\r
7c342378
MK
99 SignedData[2] = (UINT8)(((UINT16)(*WrapDataSize - 4)) >> 8);\r
100 SignedData[3] = (UINT8)(((UINT16)(*WrapDataSize - 4)) & 0xff);\r
532616bb 101\r
102 //\r
103 // Part3: 0x06, 0x09.\r
104 //\r
105 SignedData[4] = 0x06;\r
106 SignedData[5] = 0x09;\r
107\r
108 //\r
109 // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.\r
110 //\r
111 CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));\r
112\r
113 //\r
114 // Part5: 0xA0, 0x82.\r
115 //\r
116 SignedData[15] = 0xA0;\r
117 SignedData[16] = 0x82;\r
118\r
119 //\r
120 // Part6: Length2 = P7Length, in big endian.\r
121 //\r
7c342378
MK
122 SignedData[17] = (UINT8)(((UINT16)P7Length) >> 8);\r
123 SignedData[18] = (UINT8)(((UINT16)P7Length) & 0xff);\r
532616bb 124\r
125 //\r
126 // Part7: P7Data.\r
127 //\r
128 CopyMem (SignedData + 19, P7Data, P7Length);\r
129 }\r
130\r
131 *WrapFlag = Wrapped;\r
132 return TRUE;\r
133}\r
134\r
efad60c5 135/**\r
136 Pop single certificate from STACK_OF(X509).\r
137\r
138 If X509Stack, Cert, or CertSize is NULL, then return FALSE.\r
139\r
140 @param[in] X509Stack Pointer to a X509 stack object.\r
141 @param[out] Cert Pointer to a X509 certificate.\r
142 @param[out] CertSize Length of output X509 certificate in bytes.\r
2ac68e8b 143\r
efad60c5 144 @retval TRUE The X509 stack pop succeeded.\r
145 @retval FALSE The pop operation failed.\r
146\r
147**/\r
8f837243 148STATIC\r
efad60c5 149BOOLEAN\r
150X509PopCertificate (\r
7c342378
MK
151 IN VOID *X509Stack,\r
152 OUT UINT8 **Cert,\r
153 OUT UINTN *CertSize\r
efad60c5 154 )\r
155{\r
7c342378
MK
156 BIO *CertBio;\r
157 X509 *X509Cert;\r
158\r
159 STACK_OF (X509) *CertStack;\r
160 BOOLEAN Status;\r
161 INT32 Result;\r
162 BUF_MEM *Ptr;\r
163 INT32 Length;\r
164 VOID *Buffer;\r
efad60c5 165\r
166 Status = FALSE;\r
167\r
168 if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {\r
169 return Status;\r
170 }\r
171\r
7c342378 172 CertStack = (STACK_OF (X509) *) X509Stack;\r
efad60c5 173\r
174 X509Cert = sk_X509_pop (CertStack);\r
175\r
176 if (X509Cert == NULL) {\r
177 return Status;\r
178 }\r
179\r
180 Buffer = NULL;\r
181\r
182 CertBio = BIO_new (BIO_s_mem ());\r
183 if (CertBio == NULL) {\r
184 return Status;\r
185 }\r
186\r
187 Result = i2d_X509_bio (CertBio, X509Cert);\r
188 if (Result == 0) {\r
189 goto _Exit;\r
190 }\r
191\r
f56b11d2
QL
192 BIO_get_mem_ptr (CertBio, &Ptr);\r
193 Length = (INT32)(Ptr->length);\r
efad60c5 194 if (Length <= 0) {\r
195 goto _Exit;\r
196 }\r
197\r
198 Buffer = malloc (Length);\r
199 if (Buffer == NULL) {\r
200 goto _Exit;\r
201 }\r
202\r
203 Result = BIO_read (CertBio, Buffer, Length);\r
204 if (Result != Length) {\r
205 goto _Exit;\r
206 }\r
207\r
208 *Cert = Buffer;\r
209 *CertSize = Length;\r
210\r
211 Status = TRUE;\r
212\r
213_Exit:\r
214\r
215 BIO_free (CertBio);\r
216\r
217 if (!Status && (Buffer != NULL)) {\r
218 free (Buffer);\r
219 }\r
220\r
221 return Status;\r
222}\r
223\r
532616bb 224/**\r
225 Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:\r
226 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
227 in a ContentInfo structure.\r
228\r
229 If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then\r
2998af86 230 return FALSE. If P7Length overflow, then return FALSE.\r
532616bb 231\r
232 Caution: This function may receive untrusted input.\r
233 UEFI Authenticated Variable is external input, so this function will do basic\r
234 check for PKCS#7 data structure.\r
235\r
236 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
237 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
238 @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.\r
6fe575d0
LQ
239 It's caller's responsibility to free the buffer with\r
240 Pkcs7FreeSigners().\r
3702637a 241 This data structure is EFI_CERT_STACK type.\r
532616bb 242 @param[out] StackLength Length of signer's certificates in bytes.\r
243 @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.\r
6fe575d0
LQ
244 It's caller's responsibility to free the buffer with\r
245 Pkcs7FreeSigners().\r
532616bb 246 @param[out] CertLength Length of the trusted certificate in bytes.\r
247\r
248 @retval TRUE The operation is finished successfully.\r
249 @retval FALSE Error occurs during the operation.\r
250\r
251**/\r
252BOOLEAN\r
253EFIAPI\r
254Pkcs7GetSigners (\r
255 IN CONST UINT8 *P7Data,\r
256 IN UINTN P7Length,\r
257 OUT UINT8 **CertStack,\r
258 OUT UINTN *StackLength,\r
259 OUT UINT8 **TrustedCert,\r
260 OUT UINTN *CertLength\r
261 )\r
262{\r
7c342378
MK
263 PKCS7 *Pkcs7;\r
264 BOOLEAN Status;\r
265 UINT8 *SignedData;\r
266 CONST UINT8 *Temp;\r
267 UINTN SignedDataSize;\r
268 BOOLEAN Wrapped;\r
269\r
270 STACK_OF (X509) *Stack;\r
271 UINT8 Index;\r
272 UINT8 *CertBuf;\r
273 UINT8 *OldBuf;\r
274 UINTN BufferSize;\r
275 UINTN OldSize;\r
276 UINT8 *SingleCert;\r
277 UINTN SingleCertSize;\r
532616bb 278\r
279 if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||\r
7c342378
MK
280 (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX))\r
281 {\r
532616bb 282 return FALSE;\r
283 }\r
2ac68e8b 284\r
532616bb 285 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
286 if (!Status) {\r
287 return Status;\r
288 }\r
289\r
290 Status = FALSE;\r
291 Pkcs7 = NULL;\r
292 Stack = NULL;\r
293 CertBuf = NULL;\r
294 OldBuf = NULL;\r
295 SingleCert = NULL;\r
296\r
297 //\r
298 // Retrieve PKCS#7 Data (DER encoding)\r
299 //\r
300 if (SignedDataSize > INT_MAX) {\r
301 goto _Exit;\r
302 }\r
303\r
7c342378
MK
304 Temp = SignedData;\r
305 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);\r
532616bb 306 if (Pkcs7 == NULL) {\r
307 goto _Exit;\r
308 }\r
309\r
310 //\r
311 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
312 //\r
313 if (!PKCS7_type_is_signed (Pkcs7)) {\r
314 goto _Exit;\r
315 }\r
316\r
7c342378 317 Stack = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);\r
532616bb 318 if (Stack == NULL) {\r
319 goto _Exit;\r
320 }\r
321\r
322 //\r
323 // Convert CertStack to buffer in following format:\r
324 // UINT8 CertNumber;\r
325 // UINT32 Cert1Length;\r
326 // UINT8 Cert1[];\r
327 // UINT32 Cert2Length;\r
328 // UINT8 Cert2[];\r
329 // ...\r
330 // UINT32 CertnLength;\r
331 // UINT8 Certn[];\r
332 //\r
333 BufferSize = sizeof (UINT8);\r
334 OldSize = BufferSize;\r
2ac68e8b 335\r
532616bb 336 for (Index = 0; ; Index++) {\r
337 Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);\r
338 if (!Status) {\r
339 break;\r
340 }\r
341\r
342 OldSize = BufferSize;\r
343 OldBuf = CertBuf;\r
344 BufferSize = OldSize + SingleCertSize + sizeof (UINT32);\r
345 CertBuf = malloc (BufferSize);\r
346\r
347 if (CertBuf == NULL) {\r
348 goto _Exit;\r
349 }\r
350\r
351 if (OldBuf != NULL) {\r
352 CopyMem (CertBuf, OldBuf, OldSize);\r
353 free (OldBuf);\r
354 OldBuf = NULL;\r
355 }\r
356\r
7c342378 357 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)SingleCertSize);\r
532616bb 358 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);\r
359\r
360 free (SingleCert);\r
361 SingleCert = NULL;\r
362 }\r
363\r
364 if (CertBuf != NULL) {\r
365 //\r
366 // Update CertNumber.\r
367 //\r
368 CertBuf[0] = Index;\r
369\r
7c342378 370 *CertLength = BufferSize - OldSize - sizeof (UINT32);\r
532616bb 371 *TrustedCert = malloc (*CertLength);\r
372 if (*TrustedCert == NULL) {\r
373 goto _Exit;\r
374 }\r
375\r
376 CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);\r
377 *CertStack = CertBuf;\r
378 *StackLength = BufferSize;\r
7c342378 379 Status = TRUE;\r
2ac68e8b 380 }\r
532616bb 381\r
382_Exit:\r
383 //\r
384 // Release Resources\r
385 //\r
386 if (!Wrapped) {\r
387 free (SignedData);\r
388 }\r
389\r
390 if (Pkcs7 != NULL) {\r
391 PKCS7_free (Pkcs7);\r
392 }\r
393\r
394 if (Stack != NULL) {\r
7c342378 395 sk_X509_pop_free (Stack, X509_free);\r
532616bb 396 }\r
397\r
398 if (SingleCert != NULL) {\r
399 free (SingleCert);\r
400 }\r
401\r
402 if (!Status && (CertBuf != NULL)) {\r
403 free (CertBuf);\r
404 *CertStack = NULL;\r
405 }\r
406\r
407 if (OldBuf != NULL) {\r
408 free (OldBuf);\r
409 }\r
2ac68e8b 410\r
532616bb 411 return Status;\r
412}\r
413\r
414/**\r
415 Wrap function to use free() to free allocated memory for certificates.\r
416\r
417 @param[in] Certs Pointer to the certificates to be freed.\r
418\r
419**/\r
420VOID\r
421EFIAPI\r
422Pkcs7FreeSigners (\r
7c342378 423 IN UINT8 *Certs\r
532616bb 424 )\r
425{\r
426 if (Certs == NULL) {\r
427 return;\r
428 }\r
429\r
430 free (Certs);\r
431}\r
432\r
45419de6
QL
433/**\r
434 Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
435 Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
436 unchained to the signer's certificates.\r
437 The input signed data could be wrapped in a ContentInfo structure.\r
438\r
439 @param[in] P7Data Pointer to the PKCS#7 message.\r
440 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
0f5f6b3d 441 @param[out] SignerChainCerts Pointer to the certificates list chained to signer's\r
6fe575d0
LQ
442 certificate. It's caller's responsibility to free the buffer\r
443 with Pkcs7FreeSigners().\r
3702637a 444 This data structure is EFI_CERT_STACK type.\r
45419de6
QL
445 @param[out] ChainLength Length of the chained certificates list buffer in bytes.\r
446 @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's\r
6fe575d0 447 responsibility to free the buffer with Pkcs7FreeSigners().\r
3702637a 448 This data structure is EFI_CERT_STACK type.\r
45419de6
QL
449 @param[out] UnchainLength Length of the unchained certificates list buffer in bytes.\r
450\r
451 @retval TRUE The operation is finished successfully.\r
452 @retval FALSE Error occurs during the operation.\r
453\r
454**/\r
455BOOLEAN\r
456EFIAPI\r
457Pkcs7GetCertificatesList (\r
458 IN CONST UINT8 *P7Data,\r
459 IN UINTN P7Length,\r
460 OUT UINT8 **SignerChainCerts,\r
461 OUT UINTN *ChainLength,\r
462 OUT UINT8 **UnchainCerts,\r
463 OUT UINTN *UnchainLength\r
464 )\r
465{\r
7c342378
MK
466 BOOLEAN Status;\r
467 UINT8 *NewP7Data;\r
468 UINTN NewP7Length;\r
469 BOOLEAN Wrapped;\r
470 UINT8 Index;\r
471 PKCS7 *Pkcs7;\r
472 X509_STORE_CTX *CertCtx;\r
473\r
474 STACK_OF (X509) *CtxChain;\r
475 STACK_OF (X509) *CtxUntrusted;\r
476 X509 *CtxCert;\r
477\r
478 STACK_OF (X509) *Signers;\r
479 X509 *Signer;\r
480 X509 *Cert;\r
481 X509 *Issuer;\r
482 X509_NAME *IssuerName;\r
483 UINT8 *CertBuf;\r
484 UINT8 *OldBuf;\r
485 UINTN BufferSize;\r
486 UINTN OldSize;\r
487 UINT8 *SingleCert;\r
488 UINTN CertSize;\r
45419de6
QL
489\r
490 //\r
491 // Initializations\r
492 //\r
7c342378
MK
493 Status = FALSE;\r
494 NewP7Data = NULL;\r
495 Pkcs7 = NULL;\r
496 CertCtx = NULL;\r
497 CtxChain = NULL;\r
498 CtxCert = NULL;\r
499 CtxUntrusted = NULL;\r
500 Cert = NULL;\r
501 SingleCert = NULL;\r
502 CertBuf = NULL;\r
503 OldBuf = NULL;\r
504 Signers = NULL;\r
45419de6
QL
505\r
506 //\r
507 // Parameter Checking\r
508 //\r
509 if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||\r
7c342378
MK
510 (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX))\r
511 {\r
45419de6
QL
512 return Status;\r
513 }\r
514\r
515 *SignerChainCerts = NULL;\r
516 *ChainLength = 0;\r
517 *UnchainCerts = NULL;\r
518 *UnchainLength = 0;\r
519\r
520 //\r
521 // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.\r
522 //\r
523 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);\r
524 if (!Status || (NewP7Length > INT_MAX)) {\r
525 goto _Error;\r
526 }\r
527\r
528 //\r
529 // Decodes PKCS#7 SignedData\r
530 //\r
7c342378 531 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&NewP7Data, (int)NewP7Length);\r
45419de6
QL
532 if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {\r
533 goto _Error;\r
534 }\r
535\r
536 //\r
537 // Obtains Signer's Certificate from PKCS#7 data\r
538 // NOTE: Only one signer case will be handled in this function, which means SignerInfos\r
0f5f6b3d 539 // should include only one signer's certificate.\r
45419de6
QL
540 //\r
541 Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);\r
542 if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {\r
543 goto _Error;\r
544 }\r
7c342378 545\r
45419de6
QL
546 Signer = sk_X509_value (Signers, 0);\r
547\r
f56b11d2
QL
548 CertCtx = X509_STORE_CTX_new ();\r
549 if (CertCtx == NULL) {\r
550 goto _Error;\r
551 }\r
7c342378 552\r
f56b11d2 553 if (!X509_STORE_CTX_init (CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {\r
45419de6
QL
554 goto _Error;\r
555 }\r
7c342378 556\r
45419de6
QL
557 //\r
558 // Initialize Chained & Untrusted stack\r
559 //\r
f56b11d2
QL
560 CtxChain = X509_STORE_CTX_get0_chain (CertCtx);\r
561 CtxCert = X509_STORE_CTX_get0_cert (CertCtx);\r
562 if (CtxChain == NULL) {\r
563 if (((CtxChain = sk_X509_new_null ()) == NULL) ||\r
7c342378
MK
564 (!sk_X509_push (CtxChain, CtxCert)))\r
565 {\r
45419de6
QL
566 goto _Error;\r
567 }\r
568 }\r
7c342378 569\r
f56b11d2 570 CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);\r
a9fb7b78
LQ
571 if (CtxUntrusted != NULL) {\r
572 (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);\r
573 }\r
45419de6
QL
574\r
575 //\r
576 // Build certificates stack chained from Signer's certificate.\r
577 //\r
578 Cert = Signer;\r
7c342378 579 for ( ; ;) {\r
45419de6
QL
580 //\r
581 // Self-Issue checking\r
582 //\r
f56b11d2
QL
583 Issuer = NULL;\r
584 if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {\r
585 if (X509_cmp (Issuer, Cert) == 0) {\r
586 break;\r
587 }\r
45419de6
QL
588 }\r
589\r
590 //\r
591 // Found the issuer of the current certificate\r
592 //\r
f56b11d2 593 if (CtxUntrusted != NULL) {\r
7c342378 594 Issuer = NULL;\r
f56b11d2
QL
595 IssuerName = X509_get_issuer_name (Cert);\r
596 Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);\r
45419de6 597 if (Issuer != NULL) {\r
f56b11d2 598 if (!sk_X509_push (CtxChain, Issuer)) {\r
45419de6
QL
599 goto _Error;\r
600 }\r
7c342378 601\r
f56b11d2 602 (VOID)sk_X509_delete_ptr (CtxUntrusted, Issuer);\r
45419de6
QL
603\r
604 Cert = Issuer;\r
605 continue;\r
606 }\r
607 }\r
608\r
609 break;\r
610 }\r
611\r
612 //\r
613 // Converts Chained and Untrusted Certificate to Certificate Buffer in following format:\r
614 // UINT8 CertNumber;\r
615 // UINT32 Cert1Length;\r
616 // UINT8 Cert1[];\r
617 // UINT32 Cert2Length;\r
618 // UINT8 Cert2[];\r
619 // ...\r
620 // UINT32 CertnLength;\r
621 // UINT8 Certn[];\r
622 //\r
623\r
f56b11d2 624 if (CtxChain != NULL) {\r
45419de6 625 BufferSize = sizeof (UINT8);\r
45419de6
QL
626 CertBuf = NULL;\r
627\r
628 for (Index = 0; ; Index++) {\r
f56b11d2 629 Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize);\r
45419de6
QL
630 if (!Status) {\r
631 break;\r
632 }\r
633\r
634 OldSize = BufferSize;\r
635 OldBuf = CertBuf;\r
636 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
637 CertBuf = malloc (BufferSize);\r
638\r
639 if (CertBuf == NULL) {\r
640 Status = FALSE;\r
641 goto _Error;\r
642 }\r
7c342378 643\r
45419de6
QL
644 if (OldBuf != NULL) {\r
645 CopyMem (CertBuf, OldBuf, OldSize);\r
646 free (OldBuf);\r
647 OldBuf = NULL;\r
648 }\r
649\r
7c342378 650 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize);\r
45419de6
QL
651 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
652\r
653 free (SingleCert);\r
654 SingleCert = NULL;\r
655 }\r
656\r
657 if (CertBuf != NULL) {\r
658 //\r
659 // Update CertNumber.\r
660 //\r
661 CertBuf[0] = Index;\r
662\r
663 *SignerChainCerts = CertBuf;\r
664 *ChainLength = BufferSize;\r
665 }\r
666 }\r
667\r
f56b11d2 668 if (CtxUntrusted != NULL) {\r
45419de6 669 BufferSize = sizeof (UINT8);\r
45419de6
QL
670 CertBuf = NULL;\r
671\r
672 for (Index = 0; ; Index++) {\r
f56b11d2 673 Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize);\r
45419de6
QL
674 if (!Status) {\r
675 break;\r
676 }\r
677\r
678 OldSize = BufferSize;\r
679 OldBuf = CertBuf;\r
680 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
681 CertBuf = malloc (BufferSize);\r
682\r
683 if (CertBuf == NULL) {\r
684 Status = FALSE;\r
685 goto _Error;\r
686 }\r
7c342378 687\r
45419de6
QL
688 if (OldBuf != NULL) {\r
689 CopyMem (CertBuf, OldBuf, OldSize);\r
690 free (OldBuf);\r
691 OldBuf = NULL;\r
692 }\r
693\r
7c342378 694 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize);\r
45419de6
QL
695 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
696\r
697 free (SingleCert);\r
698 SingleCert = NULL;\r
699 }\r
700\r
701 if (CertBuf != NULL) {\r
702 //\r
703 // Update CertNumber.\r
704 //\r
705 CertBuf[0] = Index;\r
706\r
707 *UnchainCerts = CertBuf;\r
708 *UnchainLength = BufferSize;\r
709 }\r
710 }\r
711\r
712 Status = TRUE;\r
713\r
714_Error:\r
715 //\r
716 // Release Resources.\r
717 //\r
718 if (!Wrapped && (NewP7Data != NULL)) {\r
719 free (NewP7Data);\r
720 }\r
721\r
722 if (Pkcs7 != NULL) {\r
723 PKCS7_free (Pkcs7);\r
724 }\r
7c342378 725\r
45419de6
QL
726 sk_X509_free (Signers);\r
727\r
a9fb7b78
LQ
728 if (CertCtx != NULL) {\r
729 X509_STORE_CTX_cleanup (CertCtx);\r
730 X509_STORE_CTX_free (CertCtx);\r
731 }\r
45419de6
QL
732\r
733 if (SingleCert != NULL) {\r
734 free (SingleCert);\r
735 }\r
736\r
737 if (OldBuf != NULL) {\r
738 free (OldBuf);\r
739 }\r
740\r
741 if (!Status && (CertBuf != NULL)) {\r
742 free (CertBuf);\r
743 *SignerChainCerts = NULL;\r
744 *UnchainCerts = NULL;\r
745 }\r
746\r
747 return Status;\r
748}\r
749\r
532616bb 750/**\r
2998af86 751 Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:\r
532616bb 752 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
753 in a ContentInfo structure.\r
754\r
755 If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
2998af86 756 If P7Length, CertLength or DataLength overflow, then return FALSE.\r
532616bb 757\r
758 Caution: This function may receive untrusted input.\r
759 UEFI Authenticated Variable is external input, so this function will do basic\r
760 check for PKCS#7 data structure.\r
761\r
762 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
763 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
764 @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which\r
765 is used for certificate chain verification.\r
766 @param[in] CertLength Length of the trusted certificate in bytes.\r
767 @param[in] InData Pointer to the content to be verified.\r
768 @param[in] DataLength Length of InData in bytes.\r
769\r
770 @retval TRUE The specified PKCS#7 signed data is valid.\r
771 @retval FALSE Invalid PKCS#7 signed data.\r
772\r
773**/\r
774BOOLEAN\r
775EFIAPI\r
776Pkcs7Verify (\r
777 IN CONST UINT8 *P7Data,\r
778 IN UINTN P7Length,\r
779 IN CONST UINT8 *TrustedCert,\r
780 IN UINTN CertLength,\r
781 IN CONST UINT8 *InData,\r
782 IN UINTN DataLength\r
783 )\r
784{\r
7c342378
MK
785 PKCS7 *Pkcs7;\r
786 BIO *DataBio;\r
787 BOOLEAN Status;\r
788 X509 *Cert;\r
789 X509_STORE *CertStore;\r
790 UINT8 *SignedData;\r
791 CONST UINT8 *Temp;\r
792 UINTN SignedDataSize;\r
793 BOOLEAN Wrapped;\r
532616bb 794\r
795 //\r
796 // Check input parameters.\r
797 //\r
7c342378
MK
798 if ((P7Data == NULL) || (TrustedCert == NULL) || (InData == NULL) ||\r
799 (P7Length > INT_MAX) || (CertLength > INT_MAX) || (DataLength > INT_MAX))\r
800 {\r
532616bb 801 return FALSE;\r
802 }\r
2ac68e8b 803\r
532616bb 804 Pkcs7 = NULL;\r
532616bb 805 DataBio = NULL;\r
806 Cert = NULL;\r
807 CertStore = NULL;\r
808\r
809 //\r
810 // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
811 //\r
dda39f3a 812 if (EVP_add_digest (EVP_md5 ()) == 0) {\r
813 return FALSE;\r
814 }\r
7c342378 815\r
dda39f3a 816 if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
817 return FALSE;\r
818 }\r
7c342378 819\r
dda39f3a 820 if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
821 return FALSE;\r
822 }\r
7c342378 823\r
2ac68e8b
QL
824 if (EVP_add_digest (EVP_sha384 ()) == 0) {\r
825 return FALSE;\r
826 }\r
7c342378 827\r
2ac68e8b
QL
828 if (EVP_add_digest (EVP_sha512 ()) == 0) {\r
829 return FALSE;\r
830 }\r
7c342378 831\r
dda39f3a 832 if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {\r
833 return FALSE;\r
834 }\r
835\r
532616bb 836 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
837 if (!Status) {\r
838 return Status;\r
839 }\r
840\r
841 Status = FALSE;\r
2ac68e8b 842\r
532616bb 843 //\r
844 // Retrieve PKCS#7 Data (DER encoding)\r
845 //\r
846 if (SignedDataSize > INT_MAX) {\r
847 goto _Exit;\r
848 }\r
849\r
7c342378
MK
850 Temp = SignedData;\r
851 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);\r
532616bb 852 if (Pkcs7 == NULL) {\r
853 goto _Exit;\r
854 }\r
855\r
856 //\r
857 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
858 //\r
859 if (!PKCS7_type_is_signed (Pkcs7)) {\r
860 goto _Exit;\r
861 }\r
862\r
863 //\r
864 // Read DER-encoded root certificate and Construct X509 Certificate\r
865 //\r
1463ce18 866 Temp = TrustedCert;\r
7c342378 867 Cert = d2i_X509 (NULL, &Temp, (long)CertLength);\r
532616bb 868 if (Cert == NULL) {\r
869 goto _Exit;\r
870 }\r
871\r
872 //\r
873 // Setup X509 Store for trusted certificate\r
874 //\r
875 CertStore = X509_STORE_new ();\r
876 if (CertStore == NULL) {\r
877 goto _Exit;\r
878 }\r
7c342378 879\r
532616bb 880 if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
881 goto _Exit;\r
882 }\r
883\r
532616bb 884 //\r
885 // For generic PKCS#7 handling, InData may be NULL if the content is present\r
886 // in PKCS#7 structure. So ignore NULL checking here.\r
887 //\r
7c342378 888 DataBio = BIO_new_mem_buf (InData, (int)DataLength);\r
5b2956ea
YT
889 if (DataBio == NULL) {\r
890 goto _Exit;\r
891 }\r
892\r
68547181
DW
893 //\r
894 // Allow partial certificate chains, terminated by a non-self-signed but\r
de0408be 895 // still trusted intermediate certificate. Also disable time checks.\r
68547181 896 //\r
7c342378
MK
897 X509_STORE_set_flags (\r
898 CertStore,\r
899 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME\r
900 );\r
68547181 901\r
02ee8d3b 902 //\r
903 // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and\r
904 // doesn't support the extended key usage for Authenticode Code Signing.\r
905 // Bypass the certificate purpose checking by enabling any purposes setting.\r
906 //\r
907 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
908\r
532616bb 909 //\r
910 // Verifies the PKCS#7 signedData structure\r
911 //\r
7c342378 912 Status = (BOOLEAN)PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
532616bb 913\r
914_Exit:\r
915 //\r
916 // Release Resources\r
917 //\r
918 BIO_free (DataBio);\r
532616bb 919 X509_free (Cert);\r
920 X509_STORE_free (CertStore);\r
921 PKCS7_free (Pkcs7);\r
922\r
923 if (!Wrapped) {\r
924 OPENSSL_free (SignedData);\r
925 }\r
926\r
927 return Status;\r
afeb55e4 928}\r