]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7.c
Close the corresponding GUIDed section extraction protocol notify event in CloseSecti...
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7.c
CommitLineData
97f98500
HT
1/** @file\r
2 PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
3\r
dc204d5a
JY
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
16d2c32c 13Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
97f98500
HT
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
a8c44645 24#include "InternalCryptLib.h"\r
97f98500 25\r
97f98500
HT
26#include <openssl/objects.h>\r
27#include <openssl/x509.h>\r
28#include <openssl/pkcs7.h>\r
29\r
da9e7418 30UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };\r
97f98500 31\r
b7d320f8 32/**\r
33 Verification callback function to override any existing callbacks in OpenSSL\r
34 for intermediate certificate supports.\r
35\r
36 @param[in] Status Original status before calling this callback.\r
37 @param[in] Context X509 store context.\r
38\r
39 @retval 1 Current X509 certificate is verified successfully.\r
40 @retval 0 Verification failed.\r
41\r
42**/\r
55581f95 43int\r
44X509VerifyCb (\r
45 IN int Status,\r
46 IN X509_STORE_CTX *Context\r
47 )\r
b7d320f8 48{\r
49 X509_OBJECT *Obj;\r
55581f95 50 INTN Error;\r
51 INTN Index;\r
52 INTN Count;\r
b7d320f8 53\r
54 Obj = NULL;\r
55581f95 55 Error = (INTN) X509_STORE_CTX_get_error (Context);\r
b7d320f8 56\r
57 //\r
58 // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT and X509_V_ERR_UNABLE_TO_GET_ISSUER_\r
59 // CERT_LOCALLY mean a X509 certificate is not self signed and its issuer\r
60 // can not be found in X509_verify_cert of X509_vfy.c.\r
61 // In order to support intermediate certificate node, we override the\r
62 // errors if the certification is obtained from X509 store, i.e. it is\r
63 // a trusted ceritifcate node that is enrolled by user.\r
64 // Besides,X509_V_ERR_CERT_UNTRUSTED and X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE\r
65 // are also ignored to enable such feature.\r
66 //\r
67 if ((Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) ||\r
68 (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {\r
e8b4eb04 69 Obj = (X509_OBJECT *) malloc (sizeof (X509_OBJECT));\r
b7d320f8 70 if (Obj == NULL) {\r
71 return 0;\r
72 }\r
73\r
74 Obj->type = X509_LU_X509;\r
75 Obj->data.x509 = Context->current_cert;\r
76\r
77 CRYPTO_w_lock (CRYPTO_LOCK_X509_STORE);\r
78\r
79 if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
80 Status = 1;\r
81 } else {\r
82 //\r
83 // If any certificate in the chain is enrolled as trusted certificate,\r
84 // pass the certificate verification.\r
85 //\r
86 if (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {\r
55581f95 87 Count = (INTN) sk_X509_num (Context->chain);\r
b7d320f8 88 for (Index = 0; Index < Count; Index++) {\r
55581f95 89 Obj->data.x509 = sk_X509_value (Context->chain, (int) Index);\r
b7d320f8 90 if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
91 Status = 1;\r
92 break;\r
93 }\r
94 }\r
95 }\r
96 }\r
97\r
98 CRYPTO_w_unlock (CRYPTO_LOCK_X509_STORE);\r
99 }\r
100\r
101 if ((Error == X509_V_ERR_CERT_UNTRUSTED) ||\r
102 (Error == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) {\r
103 Status = 1;\r
104 }\r
105\r
106 if (Obj != NULL) {\r
107 OPENSSL_free (Obj);\r
108 }\r
109\r
110 return Status;\r
111}\r
112\r
113/**\r
114 Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message\r
115 Syntax Standard, version 1.5". This interface is only intended to be used for\r
116 application to perform PKCS#7 functionality validation.\r
117\r
118 @param[in] PrivateKey Pointer to the PEM-formatted private key data for\r
119 data signing.\r
120 @param[in] PrivateKeySize Size of the PEM private key data in bytes.\r
121 @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM\r
122 key data.\r
123 @param[in] InData Pointer to the content to be signed.\r
124 @param[in] InDataSize Size of InData in bytes.\r
125 @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.\r
126 @param[in] OtherCerts Pointer to an optional additional set of certificates to\r
127 include in the PKCS#7 signedData (e.g. any intermediate\r
128 CAs in the chain).\r
129 @param[out] SignedData Pointer to output PKCS#7 signedData.\r
130 @param[out] SignedDataSize Size of SignedData in bytes.\r
131\r
132 @retval TRUE PKCS#7 data signing succeeded.\r
133 @retval FALSE PKCS#7 data signing failed.\r
134\r
135**/\r
136BOOLEAN\r
137EFIAPI\r
138Pkcs7Sign (\r
139 IN CONST UINT8 *PrivateKey,\r
140 IN UINTN PrivateKeySize,\r
141 IN CONST UINT8 *KeyPassword,\r
142 IN UINT8 *InData,\r
143 IN UINTN InDataSize,\r
144 IN UINT8 *SignCert,\r
145 IN UINT8 *OtherCerts OPTIONAL,\r
146 OUT UINT8 **SignedData,\r
147 OUT UINTN *SignedDataSize\r
148 )\r
149{\r
150 BOOLEAN Status;\r
151 EVP_PKEY *Key;\r
152 BIO *DataBio;\r
153 PKCS7 *Pkcs7;\r
154 UINT8 *RsaContext;\r
155 UINT8 *P7Data;\r
da9e7418 156 UINTN P7DataSize;\r
157 UINT8 *Tmp;\r
b7d320f8 158\r
159 //\r
160 // Check input parameters.\r
161 //\r
16d2c32c 162 if (PrivateKey == NULL || KeyPassword == NULL || InData == NULL ||\r
163 SignCert == NULL || SignedData == NULL || SignedDataSize == NULL || InDataSize > INT_MAX) {\r
164 return FALSE;\r
165 }\r
da9e7418 166\r
b7d320f8 167 RsaContext = NULL;\r
168 Key = NULL;\r
169 Pkcs7 = NULL;\r
170 DataBio = NULL;\r
171 Status = FALSE;\r
172\r
173 //\r
174 // Retrieve RSA private key from PEM data.\r
175 //\r
176 Status = RsaGetPrivateKeyFromPem (\r
177 PrivateKey,\r
178 PrivateKeySize,\r
179 (CONST CHAR8 *) KeyPassword,\r
180 (VOID **) &RsaContext\r
181 );\r
182 if (!Status) {\r
183 return Status;\r
184 }\r
185\r
186 //\r
187 // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling\r
188 //\r
189 EVP_add_digest (EVP_md5());\r
190 EVP_add_digest (EVP_sha1());\r
191 EVP_add_digest (EVP_sha256());\r
192 RandomSeed (NULL, 0);\r
193\r
194 //\r
195 // Construct OpenSSL EVP_PKEY for private key.\r
196 //\r
197 Key = EVP_PKEY_new ();\r
198 if (Key == NULL) {\r
4d6afad3 199 Status = FALSE;\r
b7d320f8 200 goto _Exit;\r
201 }\r
202 Key->save_type = EVP_PKEY_RSA;\r
203 Key->type = EVP_PKEY_type (EVP_PKEY_RSA);\r
204 Key->pkey.rsa = (RSA *) RsaContext;\r
205\r
206 //\r
207 // Convert the data to be signed to BIO format. \r
208 //\r
209 DataBio = BIO_new (BIO_s_mem ());\r
210 BIO_write (DataBio, InData, (int) InDataSize);\r
211\r
212 //\r
213 // Create the PKCS#7 signedData structure.\r
214 //\r
215 Pkcs7 = PKCS7_sign (\r
216 (X509 *) SignCert,\r
217 Key,\r
218 (STACK_OF(X509) *) OtherCerts,\r
219 DataBio,\r
55581f95 220 PKCS7_BINARY | PKCS7_NOATTR | PKCS7_DETACHED\r
b7d320f8 221 );\r
222 if (Pkcs7 == NULL) {\r
4d6afad3 223 Status = FALSE;\r
b7d320f8 224 goto _Exit;\r
225 }\r
226\r
227 //\r
228 // Convert PKCS#7 signedData structure into DER-encoded buffer.\r
229 //\r
da9e7418 230 P7DataSize = i2d_PKCS7 (Pkcs7, NULL);\r
231 if (P7DataSize <= 19) {\r
4d6afad3 232 Status = FALSE;\r
b7d320f8 233 goto _Exit;\r
234 }\r
4d6afad3 235\r
e8b4eb04 236 P7Data = malloc (P7DataSize);\r
4d6afad3 237 if (P7Data == NULL) {\r
238 Status = FALSE;\r
239 goto _Exit;\r
240 }\r
241\r
da9e7418 242 Tmp = P7Data;\r
243 P7DataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &Tmp);\r
244\r
245 //\r
246 // Strip ContentInfo to content only for signeddata. The data be trimmed off\r
247 // is totally 19 bytes.\r
248 //\r
249 *SignedDataSize = P7DataSize - 19;\r
e8b4eb04 250 *SignedData = malloc (*SignedDataSize);\r
4d6afad3 251 if (*SignedData == NULL) {\r
252 Status = FALSE;\r
253 OPENSSL_free (P7Data);\r
254 goto _Exit;\r
255 }\r
256\r
da9e7418 257 CopyMem (*SignedData, P7Data + 19, *SignedDataSize);\r
258 \r
259 OPENSSL_free (P7Data);\r
b7d320f8 260\r
261 Status = TRUE;\r
262\r
263_Exit:\r
264 //\r
265 // Release Resources\r
266 //\r
267 if (RsaContext != NULL) {\r
268 RsaFree (RsaContext);\r
269 if (Key != NULL) {\r
270 Key->pkey.rsa = NULL;\r
271 }\r
272 }\r
273\r
274 if (Key != NULL) {\r
275 EVP_PKEY_free (Key);\r
276 }\r
277\r
278 if (DataBio != NULL) {\r
279 BIO_free (DataBio);\r
280 }\r
281\r
282 if (Pkcs7 != NULL) {\r
283 PKCS7_free (Pkcs7);\r
284 }\r
285\r
286 return Status;\r
287}\r
288\r
97f98500 289/**\r
e8b4eb04 290 Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
291 a new structure to wrap P7Data.\r
97f98500 292\r
dc204d5a
JY
293 Caution: This function may receive untrusted input.\r
294 UEFI Authenticated Variable is external input, so this function will do basic\r
295 check for PKCS#7 data structure.\r
296\r
97f98500
HT
297 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
298 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
e8b4eb04 299 @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise\r
300 return FALSE.\r
301 @param[out] WrapData If return status of this function is TRUE: \r
302 1) when WrapFlag is TRUE, pointer to P7Data.\r
303 2) when WrapFlag is FALSE, pointer to a new ContentInfo\r
304 structure. It's caller's responsibility to free this\r
305 buffer.\r
306 @param[out] WrapDataSize Length of ContentInfo structure in bytes.\r
307\r
308 @retval TRUE The operation is finished successfully.\r
309 @retval FALSE The operation is failed due to lack of resources.\r
97f98500
HT
310\r
311**/\r
312BOOLEAN\r
e8b4eb04 313WrapPkcs7Data (\r
97f98500
HT
314 IN CONST UINT8 *P7Data,\r
315 IN UINTN P7Length,\r
e8b4eb04 316 OUT BOOLEAN *WrapFlag,\r
317 OUT UINT8 **WrapData,\r
318 OUT UINTN *WrapDataSize\r
97f98500
HT
319 )\r
320{\r
e8b4eb04 321 BOOLEAN Wrapped;\r
322 UINT8 *SignedData;\r
97f98500 323\r
da9e7418 324 //\r
325 // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
326 //\r
327 Wrapped = FALSE;\r
328 if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {\r
329 if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {\r
330 if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {\r
331 Wrapped = TRUE;\r
332 }\r
333 }\r
334 }\r
335\r
336 if (Wrapped) {\r
e8b4eb04 337 *WrapData = (UINT8 *) P7Data;\r
338 *WrapDataSize = P7Length;\r
da9e7418 339 } else {\r
340 //\r
341 // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.\r
342 //\r
e8b4eb04 343 *WrapDataSize = P7Length + 19;\r
344 *WrapData = malloc (*WrapDataSize);\r
345 if (*WrapData == NULL) {\r
346 *WrapFlag = Wrapped;\r
da9e7418 347 return FALSE;\r
348 }\r
349\r
e8b4eb04 350 SignedData = *WrapData;\r
351\r
da9e7418 352 //\r
353 // Part1: 0x30, 0x82.\r
354 //\r
355 SignedData[0] = 0x30;\r
356 SignedData[1] = 0x82;\r
357\r
358 //\r
359 // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
360 //\r
e8b4eb04 361 SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);\r
362 SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);\r
da9e7418 363\r
364 //\r
365 // Part3: 0x06, 0x09.\r
366 //\r
367 SignedData[4] = 0x06;\r
368 SignedData[5] = 0x09;\r
369\r
370 //\r
371 // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.\r
372 //\r
373 CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));\r
374\r
375 //\r
376 // Part5: 0xA0, 0x82.\r
377 //\r
378 SignedData[15] = 0xA0;\r
379 SignedData[16] = 0x82;\r
380\r
381 //\r
382 // Part6: Length2 = P7Length, in big endian.\r
383 //\r
384 SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);\r
385 SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);\r
386\r
387 //\r
388 // Part7: P7Data.\r
389 //\r
390 CopyMem (SignedData + 19, P7Data, P7Length);\r
391 }\r
e8b4eb04 392\r
393 *WrapFlag = Wrapped;\r
394 return TRUE;\r
395}\r
396\r
397/**\r
398 Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:\r
399 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
400 in a ContentInfo structure.\r
401\r
402 If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then\r
403 return FALSE. If P7Length overflow, then return FAlSE.\r
404\r
dc204d5a
JY
405 Caution: This function may receive untrusted input.\r
406 UEFI Authenticated Variable is external input, so this function will do basic\r
407 check for PKCS#7 data structure.\r
408\r
e8b4eb04 409 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
410 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
411 @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.\r
412 It's caller's responsiblity to free the buffer.\r
413 @param[out] StackLength Length of signer's certificates in bytes.\r
414 @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.\r
415 It's caller's responsiblity to free the buffer.\r
416 @param[out] CertLength Length of the trusted certificate in bytes.\r
417\r
418 @retval TRUE The operation is finished successfully.\r
419 @retval FALSE Error occurs during the operation.\r
420\r
421**/\r
422BOOLEAN\r
423EFIAPI\r
424Pkcs7GetSigners (\r
425 IN CONST UINT8 *P7Data,\r
426 IN UINTN P7Length,\r
427 OUT UINT8 **CertStack,\r
428 OUT UINTN *StackLength,\r
429 OUT UINT8 **TrustedCert,\r
430 OUT UINTN *CertLength\r
431 )\r
432{\r
433 PKCS7 *Pkcs7;\r
434 BOOLEAN Status;\r
435 UINT8 *SignedData;\r
436 UINT8 *Temp;\r
437 UINTN SignedDataSize;\r
438 BOOLEAN Wrapped;\r
439 STACK_OF(X509) *Stack;\r
440 UINT8 Index;\r
441 UINT8 *CertBuf;\r
442 UINT8 *OldBuf;\r
443 UINTN BufferSize;\r
444 UINTN OldSize;\r
445 UINT8 *SingleCert;\r
446 UINTN SingleCertSize;\r
447\r
448 if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||\r
449 (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) {\r
450 return FALSE;\r
451 }\r
452 \r
453 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
454 if (!Status) {\r
455 return Status;\r
456 }\r
457\r
458 Status = FALSE;\r
459 Pkcs7 = NULL;\r
460 Stack = NULL;\r
461 CertBuf = NULL;\r
462 OldBuf = NULL;\r
463 SingleCert = NULL;\r
464\r
465 //\r
466 // Retrieve PKCS#7 Data (DER encoding)\r
467 //\r
468 if (SignedDataSize > INT_MAX) {\r
469 goto _Exit;\r
470 }\r
471\r
472 Temp = SignedData;\r
473 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);\r
474 if (Pkcs7 == NULL) {\r
475 goto _Exit;\r
476 }\r
477\r
478 //\r
479 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
480 //\r
481 if (!PKCS7_type_is_signed (Pkcs7)) {\r
482 goto _Exit;\r
483 }\r
484\r
485 Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY);\r
486 if (Stack == NULL) {\r
487 goto _Exit;\r
488 }\r
489\r
490 //\r
491 // Convert CertStack to buffer in following format:\r
492 // UINT8 CertNumber;\r
493 // UINT32 Cert1Length;\r
494 // UINT8 Cert1[];\r
495 // UINT32 Cert2Length;\r
496 // UINT8 Cert2[];\r
497 // ...\r
498 // UINT32 CertnLength;\r
499 // UINT8 Certn[];\r
500 //\r
501 BufferSize = sizeof (UINT8);\r
502 OldSize = BufferSize;\r
503 \r
504 for (Index = 0; ; Index++) {\r
505 Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);\r
506 if (!Status) {\r
507 break;\r
508 }\r
509\r
510 OldSize = BufferSize;\r
511 OldBuf = CertBuf;\r
512 BufferSize = OldSize + SingleCertSize + sizeof (UINT32);\r
513 CertBuf = malloc (BufferSize);\r
514\r
515 if (CertBuf == NULL) {\r
516 goto _Exit;\r
517 }\r
518\r
519 if (OldBuf != NULL) {\r
520 CopyMem (CertBuf, OldBuf, OldSize);\r
521 free (OldBuf);\r
522 OldBuf = NULL;\r
523 }\r
524\r
525 WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize);\r
526 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);\r
527\r
528 free (SingleCert);\r
529 SingleCert = NULL;\r
530 }\r
531\r
532 if (CertBuf != NULL) {\r
533 //\r
534 // Update CertNumber.\r
535 //\r
536 CertBuf[0] = Index;\r
537\r
538 *CertLength = BufferSize - OldSize - sizeof (UINT32);\r
539 *TrustedCert = malloc (*CertLength);\r
540 if (*TrustedCert == NULL) {\r
541 goto _Exit;\r
542 }\r
543\r
544 CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);\r
545 *CertStack = CertBuf;\r
546 *StackLength = BufferSize;\r
547 Status = TRUE;\r
548 } \r
549\r
550_Exit:\r
551 //\r
552 // Release Resources\r
553 //\r
554 if (!Wrapped) {\r
555 free (SignedData);\r
556 }\r
557\r
558 if (Pkcs7 != NULL) {\r
559 PKCS7_free (Pkcs7);\r
560 }\r
561\r
562 if (Stack != NULL) {\r
563 sk_X509_pop_free(Stack, X509_free);\r
564 }\r
565\r
566 if (SingleCert != NULL) {\r
567 free (SingleCert);\r
568 }\r
569\r
570 if (!Status && (CertBuf != NULL)) {\r
571 free (CertBuf);\r
572 *CertStack = NULL;\r
573 }\r
574\r
575 if (OldBuf != NULL) {\r
576 free (OldBuf);\r
577 }\r
578 \r
579 return Status;\r
580}\r
581\r
582/**\r
583 Wrap function to use free() to free allocated memory for certificates.\r
584\r
585 @param[in] Certs Pointer to the certificates to be freed.\r
586\r
587**/\r
588VOID\r
589EFIAPI\r
590Pkcs7FreeSigners (\r
591 IN UINT8 *Certs\r
592 )\r
593{\r
594 if (Certs == NULL) {\r
595 return;\r
596 }\r
597\r
598 free (Certs);\r
599}\r
600\r
601/**\r
602 Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:\r
603 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
604 in a ContentInfo structure.\r
605\r
606 If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
607 If P7Length, CertLength or DataLength overflow, then return FAlSE.\r
608\r
dc204d5a
JY
609 Caution: This function may receive untrusted input.\r
610 UEFI Authenticated Variable is external input, so this function will do basic\r
611 check for PKCS#7 data structure.\r
612\r
e8b4eb04 613 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
614 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
615 @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which\r
616 is used for certificate chain verification.\r
617 @param[in] CertLength Length of the trusted certificate in bytes.\r
618 @param[in] InData Pointer to the content to be verified.\r
619 @param[in] DataLength Length of InData in bytes.\r
620\r
621 @retval TRUE The specified PKCS#7 signed data is valid.\r
622 @retval FALSE Invalid PKCS#7 signed data.\r
623\r
624**/\r
625BOOLEAN\r
626EFIAPI\r
627Pkcs7Verify (\r
628 IN CONST UINT8 *P7Data,\r
629 IN UINTN P7Length,\r
630 IN CONST UINT8 *TrustedCert,\r
631 IN UINTN CertLength,\r
632 IN CONST UINT8 *InData,\r
633 IN UINTN DataLength\r
634 )\r
635{\r
636 PKCS7 *Pkcs7;\r
637 BIO *CertBio;\r
638 BIO *DataBio;\r
639 BOOLEAN Status;\r
640 X509 *Cert;\r
641 X509_STORE *CertStore;\r
642 UINT8 *SignedData;\r
643 UINT8 *Temp;\r
644 UINTN SignedDataSize;\r
645 BOOLEAN Wrapped;\r
646\r
647 //\r
648 // Check input parameters.\r
649 //\r
650 if (P7Data == NULL || TrustedCert == NULL || InData == NULL || \r
651 P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {\r
652 return FALSE;\r
653 }\r
654 \r
655 Pkcs7 = NULL;\r
656 CertBio = NULL;\r
657 DataBio = NULL;\r
658 Cert = NULL;\r
659 CertStore = NULL;\r
660\r
661 //\r
662 // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
663 //\r
664 EVP_add_digest (EVP_md5());\r
665 EVP_add_digest (EVP_sha1());\r
666 EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA);\r
667 EVP_add_digest (EVP_sha256());\r
668\r
669 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
670 if (!Status) {\r
671 return Status;\r
672 }\r
c4de8e2e 673\r
674 Status = FALSE;\r
da9e7418 675 \r
97f98500
HT
676 //\r
677 // Retrieve PKCS#7 Data (DER encoding)\r
678 //\r
da9e7418 679 if (SignedDataSize > INT_MAX) {\r
680 goto _Exit;\r
681 }\r
682\r
683 Temp = SignedData;\r
421fb3b5 684 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);\r
97f98500
HT
685 if (Pkcs7 == NULL) {\r
686 goto _Exit;\r
687 }\r
688\r
689 //\r
690 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
691 //\r
692 if (!PKCS7_type_is_signed (Pkcs7)) {\r
693 goto _Exit;\r
694 }\r
695\r
97f98500
HT
696 //\r
697 // Read DER-encoded root certificate and Construct X509 Certificate\r
698 //\r
699 CertBio = BIO_new (BIO_s_mem ());\r
700 BIO_write (CertBio, TrustedCert, (int)CertLength);\r
701 if (CertBio == NULL) {\r
702 goto _Exit;\r
703 }\r
704 Cert = d2i_X509_bio (CertBio, NULL);\r
705 if (Cert == NULL) {\r
706 goto _Exit;\r
707 }\r
708\r
709 //\r
710 // Setup X509 Store for trusted certificate\r
711 //\r
712 CertStore = X509_STORE_new ();\r
713 if (CertStore == NULL) {\r
714 goto _Exit;\r
715 }\r
716 if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
717 goto _Exit;\r
718 }\r
719\r
b7d320f8 720 //\r
721 // Register customized X509 verification callback function to support\r
722 // trusted intermediate certificate anchor.\r
723 //\r
724 CertStore->verify_cb = X509VerifyCb;\r
725\r
97f98500
HT
726 //\r
727 // For generic PKCS#7 handling, InData may be NULL if the content is present\r
728 // in PKCS#7 structure. So ignore NULL checking here.\r
729 //\r
730 DataBio = BIO_new (BIO_s_mem ());\r
731 BIO_write (DataBio, InData, (int)DataLength);\r
732\r
733 //\r
734 // Verifies the PKCS#7 signedData structure\r
735 //\r
b7d320f8 736 Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
97f98500
HT
737\r
738_Exit:\r
739 //\r
740 // Release Resources\r
741 //\r
742 BIO_free (DataBio);\r
743 BIO_free (CertBio);\r
744 X509_free (Cert);\r
745 X509_STORE_free (CertStore);\r
746 PKCS7_free (Pkcs7);\r
747\r
da9e7418 748 if (!Wrapped) {\r
749 OPENSSL_free (SignedData);\r
750 }\r
751\r
97f98500
HT
752 return Status;\r
753}\r