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