]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
CryptoPkg/BaseCryptLib: Add NULL pointer checks in DH and P7Verify
[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
QL
614 BufferSize = sizeof (UINT8);\r
615 OldSize = BufferSize;\r
616 CertBuf = NULL;\r
617\r
618 for (Index = 0; ; Index++) {\r
f56b11d2 619 Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize);\r
45419de6
QL
620 if (!Status) {\r
621 break;\r
622 }\r
623\r
624 OldSize = BufferSize;\r
625 OldBuf = CertBuf;\r
626 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
627 CertBuf = malloc (BufferSize);\r
628\r
629 if (CertBuf == NULL) {\r
630 Status = FALSE;\r
631 goto _Error;\r
632 }\r
633 if (OldBuf != NULL) {\r
634 CopyMem (CertBuf, OldBuf, OldSize);\r
635 free (OldBuf);\r
636 OldBuf = NULL;\r
637 }\r
638\r
639 WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);\r
640 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
641\r
642 free (SingleCert);\r
643 SingleCert = NULL;\r
644 }\r
645\r
646 if (CertBuf != NULL) {\r
647 //\r
648 // Update CertNumber.\r
649 //\r
650 CertBuf[0] = Index;\r
651\r
652 *SignerChainCerts = CertBuf;\r
653 *ChainLength = BufferSize;\r
654 }\r
655 }\r
656\r
f56b11d2 657 if (CtxUntrusted != NULL) {\r
45419de6
QL
658 BufferSize = sizeof (UINT8);\r
659 OldSize = BufferSize;\r
660 CertBuf = NULL;\r
661\r
662 for (Index = 0; ; Index++) {\r
f56b11d2 663 Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize);\r
45419de6
QL
664 if (!Status) {\r
665 break;\r
666 }\r
667\r
668 OldSize = BufferSize;\r
669 OldBuf = CertBuf;\r
670 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
671 CertBuf = malloc (BufferSize);\r
672\r
673 if (CertBuf == NULL) {\r
674 Status = FALSE;\r
675 goto _Error;\r
676 }\r
677 if (OldBuf != NULL) {\r
678 CopyMem (CertBuf, OldBuf, OldSize);\r
679 free (OldBuf);\r
680 OldBuf = NULL;\r
681 }\r
682\r
683 WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);\r
684 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
685\r
686 free (SingleCert);\r
687 SingleCert = NULL;\r
688 }\r
689\r
690 if (CertBuf != NULL) {\r
691 //\r
692 // Update CertNumber.\r
693 //\r
694 CertBuf[0] = Index;\r
695\r
696 *UnchainCerts = CertBuf;\r
697 *UnchainLength = BufferSize;\r
698 }\r
699 }\r
700\r
701 Status = TRUE;\r
702\r
703_Error:\r
704 //\r
705 // Release Resources.\r
706 //\r
707 if (!Wrapped && (NewP7Data != NULL)) {\r
708 free (NewP7Data);\r
709 }\r
710\r
711 if (Pkcs7 != NULL) {\r
712 PKCS7_free (Pkcs7);\r
713 }\r
714 sk_X509_free (Signers);\r
715\r
a9fb7b78
LQ
716 if (CertCtx != NULL) {\r
717 X509_STORE_CTX_cleanup (CertCtx);\r
718 X509_STORE_CTX_free (CertCtx);\r
719 }\r
45419de6
QL
720\r
721 if (SingleCert != NULL) {\r
722 free (SingleCert);\r
723 }\r
724\r
725 if (OldBuf != NULL) {\r
726 free (OldBuf);\r
727 }\r
728\r
729 if (!Status && (CertBuf != NULL)) {\r
730 free (CertBuf);\r
731 *SignerChainCerts = NULL;\r
732 *UnchainCerts = NULL;\r
733 }\r
734\r
735 return Status;\r
736}\r
737\r
532616bb 738/**\r
2998af86 739 Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:\r
532616bb 740 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
741 in a ContentInfo structure.\r
742\r
743 If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
2998af86 744 If P7Length, CertLength or DataLength overflow, then return FALSE.\r
532616bb 745\r
746 Caution: This function may receive untrusted input.\r
747 UEFI Authenticated Variable is external input, so this function will do basic\r
748 check for PKCS#7 data structure.\r
749\r
750 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
751 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
752 @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which\r
753 is used for certificate chain verification.\r
754 @param[in] CertLength Length of the trusted certificate in bytes.\r
755 @param[in] InData Pointer to the content to be verified.\r
756 @param[in] DataLength Length of InData in bytes.\r
757\r
758 @retval TRUE The specified PKCS#7 signed data is valid.\r
759 @retval FALSE Invalid PKCS#7 signed data.\r
760\r
761**/\r
762BOOLEAN\r
763EFIAPI\r
764Pkcs7Verify (\r
765 IN CONST UINT8 *P7Data,\r
766 IN UINTN P7Length,\r
767 IN CONST UINT8 *TrustedCert,\r
768 IN UINTN CertLength,\r
769 IN CONST UINT8 *InData,\r
770 IN UINTN DataLength\r
771 )\r
772{\r
773 PKCS7 *Pkcs7;\r
532616bb 774 BIO *DataBio;\r
775 BOOLEAN Status;\r
776 X509 *Cert;\r
777 X509_STORE *CertStore;\r
778 UINT8 *SignedData;\r
1463ce18 779 CONST UINT8 *Temp;\r
532616bb 780 UINTN SignedDataSize;\r
781 BOOLEAN Wrapped;\r
782\r
783 //\r
784 // Check input parameters.\r
785 //\r
2ac68e8b 786 if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||\r
532616bb 787 P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {\r
788 return FALSE;\r
789 }\r
2ac68e8b 790\r
532616bb 791 Pkcs7 = NULL;\r
532616bb 792 DataBio = NULL;\r
793 Cert = NULL;\r
794 CertStore = NULL;\r
795\r
796 //\r
797 // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
798 //\r
dda39f3a 799 if (EVP_add_digest (EVP_md5 ()) == 0) {\r
800 return FALSE;\r
801 }\r
802 if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
803 return FALSE;\r
804 }\r
805 if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
806 return FALSE;\r
807 }\r
2ac68e8b
QL
808 if (EVP_add_digest (EVP_sha384 ()) == 0) {\r
809 return FALSE;\r
810 }\r
811 if (EVP_add_digest (EVP_sha512 ()) == 0) {\r
812 return FALSE;\r
813 }\r
dda39f3a 814 if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {\r
815 return FALSE;\r
816 }\r
817\r
532616bb 818 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
819 if (!Status) {\r
820 return Status;\r
821 }\r
822\r
823 Status = FALSE;\r
2ac68e8b 824\r
532616bb 825 //\r
826 // Retrieve PKCS#7 Data (DER encoding)\r
827 //\r
828 if (SignedDataSize > INT_MAX) {\r
829 goto _Exit;\r
830 }\r
831\r
832 Temp = SignedData;\r
833 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);\r
834 if (Pkcs7 == NULL) {\r
835 goto _Exit;\r
836 }\r
837\r
838 //\r
839 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
840 //\r
841 if (!PKCS7_type_is_signed (Pkcs7)) {\r
842 goto _Exit;\r
843 }\r
844\r
845 //\r
846 // Read DER-encoded root certificate and Construct X509 Certificate\r
847 //\r
1463ce18
QL
848 Temp = TrustedCert;\r
849 Cert = d2i_X509 (NULL, &Temp, (long) CertLength);\r
532616bb 850 if (Cert == NULL) {\r
851 goto _Exit;\r
852 }\r
853\r
854 //\r
855 // Setup X509 Store for trusted certificate\r
856 //\r
857 CertStore = X509_STORE_new ();\r
858 if (CertStore == NULL) {\r
859 goto _Exit;\r
860 }\r
861 if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
862 goto _Exit;\r
863 }\r
864\r
532616bb 865 //\r
866 // For generic PKCS#7 handling, InData may be NULL if the content is present\r
867 // in PKCS#7 structure. So ignore NULL checking here.\r
868 //\r
869 DataBio = BIO_new (BIO_s_mem ());\r
5b2956ea
YT
870 if (DataBio == NULL) {\r
871 goto _Exit;\r
872 }\r
873\r
874 if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {\r
875 goto _Exit;\r
876 }\r
532616bb 877\r
68547181
DW
878 //\r
879 // Allow partial certificate chains, terminated by a non-self-signed but\r
de0408be 880 // still trusted intermediate certificate. Also disable time checks.\r
68547181 881 //\r
de0408be
DW
882 X509_STORE_set_flags (CertStore,\r
883 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);\r
68547181 884\r
02ee8d3b 885 //\r
886 // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and\r
887 // doesn't support the extended key usage for Authenticode Code Signing.\r
888 // Bypass the certificate purpose checking by enabling any purposes setting.\r
889 //\r
890 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
891\r
532616bb 892 //\r
893 // Verifies the PKCS#7 signedData structure\r
894 //\r
895 Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
896\r
897_Exit:\r
898 //\r
899 // Release Resources\r
900 //\r
901 BIO_free (DataBio);\r
532616bb 902 X509_free (Cert);\r
903 X509_STORE_free (CertStore);\r
904 PKCS7_free (Pkcs7);\r
905\r
906 if (!Wrapped) {\r
907 OPENSSL_free (SignedData);\r
908 }\r
909\r
910 return Status;\r
afeb55e4
QL
911}\r
912\r
913/**\r
914 Extracts the attached content from a PKCS#7 signed data if existed. The input signed\r
915 data could be wrapped in a ContentInfo structure.\r
916\r
917 If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,\r
2998af86 918 then return FALSE. If the P7Data is not correctly formatted, then return FALSE.\r
afeb55e4
QL
919\r
920 Caution: This function may receive untrusted input. So this function will do\r
921 basic check for PKCS#7 data structure.\r
922\r
923 @param[in] P7Data Pointer to the PKCS#7 signed data to process.\r
924 @param[in] P7Length Length of the PKCS#7 signed data in bytes.\r
925 @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.\r
210abffd 926 It's caller's responsibility to free the buffer.\r
afeb55e4
QL
927 @param[out] ContentSize The size of the extracted content in bytes.\r
928\r
929 @retval TRUE The P7Data was correctly formatted for processing.\r
930 @retval FALSE The P7Data was not correctly formatted for processing.\r
931\r
0c9fc4b1 932**/\r
afeb55e4
QL
933BOOLEAN\r
934EFIAPI\r
935Pkcs7GetAttachedContent (\r
936 IN CONST UINT8 *P7Data,\r
937 IN UINTN P7Length,\r
938 OUT VOID **Content,\r
939 OUT UINTN *ContentSize\r
940 )\r
941{\r
942 BOOLEAN Status;\r
943 PKCS7 *Pkcs7;\r
944 UINT8 *SignedData;\r
945 UINTN SignedDataSize;\r
946 BOOLEAN Wrapped;\r
947 CONST UINT8 *Temp;\r
948 ASN1_OCTET_STRING *OctStr;\r
949\r
afeb55e4
QL
950 //\r
951 // Check input parameter.\r
952 //\r
953 if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {\r
954 return FALSE;\r
955 }\r
956\r
2aabd146
QL
957 *Content = NULL;\r
958 Pkcs7 = NULL;\r
959 SignedData = NULL;\r
960 OctStr = NULL;\r
961\r
afeb55e4
QL
962 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
963 if (!Status || (SignedDataSize > INT_MAX)) {\r
964 goto _Exit;\r
965 }\r
966\r
967 Status = FALSE;\r
968\r
969 //\r
970 // Decoding PKCS#7 SignedData\r
971 //\r
972 Temp = SignedData;\r
973 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);\r
974 if (Pkcs7 == NULL) {\r
975 goto _Exit;\r
976 }\r
977\r
978 //\r
979 // The type of Pkcs7 must be signedData\r
980 //\r
981 if (!PKCS7_type_is_signed (Pkcs7)) {\r
982 goto _Exit;\r
983 }\r
984\r
985 //\r
986 // Check for detached or attached content\r
987 //\r
988 if (PKCS7_get_detached (Pkcs7)) {\r
989 //\r
990 // No Content supplied for PKCS7 detached signedData\r
991 //\r
992 *Content = NULL;\r
993 *ContentSize = 0;\r
994 } else {\r
995 //\r
996 // Retrieve the attached content in PKCS7 signedData\r
997 //\r
998 OctStr = Pkcs7->d.sign->contents->d.data;\r
999 if ((OctStr->length > 0) && (OctStr->data != NULL)) {\r
1000 *ContentSize = OctStr->length;\r
1001 *Content = malloc (*ContentSize);\r
2aabd146
QL
1002 if (*Content == NULL) {\r
1003 *ContentSize = 0;\r
1004 goto _Exit;\r
1005 }\r
afeb55e4
QL
1006 CopyMem (*Content, OctStr->data, *ContentSize);\r
1007 }\r
1008 }\r
1009 Status = TRUE;\r
1010\r
1011_Exit:\r
1012 //\r
1013 // Release Resources\r
1014 //\r
1015 PKCS7_free (Pkcs7);\r
1016\r
1017 if (!Wrapped) {\r
1018 OPENSSL_free (SignedData);\r
1019 }\r
1020\r
1021 return Status;\r
1022}\r