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