summaryrefslogtreecommitdiff
path: root/Core/EM/CryptoPkg/CryptoPei.c
blob: 1945986e83a6cf21833eb5609a8a3b626eb7052a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
//**********************************************************************
//**********************************************************************
//**                                                                  **
//**        (C)Copyright 1985-2013, American Megatrends, Inc.         **
//**                                                                  **
//**                       All Rights Reserved.                       **
//**                                                                  **
//**        5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093         **
//**                                                                  **
//**                       Phone: (770)-246-8600                      **
//**                                                                  **
//**********************************************************************
//**********************************************************************
//**********************************************************************
// $Header: /Alaska/BIN/Modules/CryptoPkg/CryptoPei.c 15    8/01/13 6:27p Alexp $
//
// $Revision: 15 $
//
// $Date: 8/01/13 6:27p $
//**********************************************************************
// Revision History
// ----------------
// $Log: /Alaska/BIN/Modules/CryptoPkg/CryptoPei.c $
// 
// 15    8/01/13 6:27p Alexp
// Comment out a check for FwKey location to be mapped to Flash FV_BB
// In some cases FindFFS for FwKey may return a location outside of Flash
// space. 
// Will have the logic fixed in the next label.
// 
// 14    7/01/13 5:24p Alexp
// CryptoPei_Init(): fix addr typecasting for pFwKeyHob->KeyAddress
// 
// 13    6/20/13 1:55p Alexp
// Impove FwKey handling. CryptoPEI pass FwKey location to Dxe via Hob
// Add mor parameter checking including 
//  check for FwKey location to be mapped to Flash FV_BB
// 
// 12    5/23/13 12:04p Alexp
// Add dependency on PKCS7_PEI_Support switch to turn off Pkcs7 support in
// CryptoPEI. Saves ~8kb of space
// 
// 11    12/28/12 3:05p Alexp
// CryptoGetRawImage(): calculate raw Key size inside FwKey ffs file
// 
// 10    12/19/12 10:31a Alexp
// code modify to meet "cppcheck" style & performance suggestions
// 
// 8     11/15/12 9:28a Alexp
// update Pkcs7Verify help header
// 
// 7     11/14/12 6:28p Alexp
// rename ppPS to gPeiServices in order to keep backward compatibility for
// older Secure Flash eModules
// 
// 6     11/13/12 11:50a Alexp
// EIP#105015: Add Pkcs#7 Cert Verification function in Crypto PPI
// Add handling of x509 formatted FW Key in FFS files
// 
// 5     7/25/12 10:00a Alexp
// cleaned comments in Hash Hdr
// 
// 4     3/12/12 4:11p Alexp
// do not install Crypto PPI on S3 resume.
// 
// 3     3/02/12 10:43a Alexp
// Remove dependency on SDL Token FWKEY_FORMAT to determine format of PR
// Key file
// Try different Ffs GUIDs to select proper Key format: SHA or RSA
// 
// 2     2/29/12 4:01p Alexp
// 1. Use SDL Token FWKEY_FORMAT to define format of PR Key file: Hash or
// RSA2048
// 2. Modify VerifyKey to account for PR Key in SHA256 format
// 
// 1     6/13/11 5:19p Alexp
// 
// 1     5/06/11 6:11p Alexp
// initial module release
// 
// 10    4/22/11 4:19p Alexp
// fix GetRaw file
// 
// 9     4/18/11 7:09p Alexp
// 
// 8     4/11/11 12:53p Alexp
// remove Verify Capsule from Crypto PPI. Function moved to SecRecovery.c
// 
// 7     4/08/11 1:33p Alexp
// This revision Supports single PK(FwSign) Ffs file with SigDb with
// multiple Keys
// 
// 6     4/05/11 6:31p Alexp
// 
// 5     3/21/11 6:58p Alexp
// 
// 4     3/15/11 12:48p Alexp
// 
// 3     3/14/11 3:26p Alexp
// add provision to handle multiple Platform Signing keys.
// rom may containg multiple Keys as FFS files with same Guid
// 
// 2     3/11/11 6:51p Alexp
// 
// 1     3/10/11 4:52p Alexp
// 
// 2     2/28/11 6:46p Alexp
// 
// 1     2/18/11 5:42p Alexp
// 
//**********************************************************************
#include <Token.h>
#include <AmiPeiLib.h>
#include "PPI\LoadFile.h"
#include <Protocol\Hash.h>
#include <PPI\CryptoPPI.h>
#include "AmiCertificate.h"

#include <cryptlib.h>

//
// Global variables
//

// Although ShaXXXGuid global variables are defined in EDK's EdkProtocol Lib, but linking it adds additional 20k in debug mode.
static EFI_GUID gEfiHashAlgorithmSha1Guid   = EFI_HASH_ALGORITHM_SHA1_GUID;
static EFI_GUID gEfiHashAlgorithmSha256Guid = EFI_HASH_ALGORITHM_SHA256_GUID;
static EFI_GUID gPKeyGuid                   = PR_KEY_GUID;

// Hardwired at Build time. Supported formats: RSA2048, HASH256 Key Certs
static EFI_GUID gPKeyFileRsa2048Guid = PR_KEY_FFS_FILE_RAW_GUID; 
static EFI_GUID gPKeyFileSha256Guid = PR_KEY_FFS_FILE_SHA256_GUID;
static EFI_GUID gPKeyFileX509Guid = PR_KEY_FFS_FILE_X509_GUID;

static EFI_GUID gEfiCertSha256Guid = EFI_CERT_SHA256_GUID;
static EFI_GUID gEfiCertRsa2048Guid = EFI_CERT_RSA2048_GUID;
static EFI_GUID gEfiCertX509Guid = EFI_CERT_X509;

static EFI_GUID *gKeyFileGuid [] = {
    &gPKeyFileX509Guid,
    &gPKeyFileRsa2048Guid,
    &gPKeyFileSha256Guid,
    NULL
};
static EFI_GUID *gKeyTypeGuid [] = {
    &gEfiCertX509Guid,
    &gEfiCertRsa2048Guid,
    &gEfiCertSha256Guid,
    NULL
};

EFI_PEI_SERVICES  **gPeiServices;
FW_KEY_HOB         *pFwKeyHob = NULL;
//
// SDL defined Public Exponent E of RSA Key.
//
const UINT8  KeyE[] = {E_CONST}; // 0x10001
const UINT32 LenE = sizeof(KeyE);
//    PKCS_1 PSS Signature constatnt. Size of the Salt (random data) field in PSS signature.
const INT32  saltlen = PSS_SIG_SALTLEN; // 8 
static UINT8 DecriptedSig[DEFAULT_RSA_SIG_LEN];
//----------------------------------------------------------------------------
// Crypto Function prototypes
//----------------------------------------------------------------------------
EFI_STATUS
PeiHash (
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI      *This,
  IN CONST EFI_GUID               *HashAlgorithm,
  IN UINTN                        num_elem,
  IN CONST UINT8                  *addr[],
  IN CONST UINTN                  *len,
  OUT UINT8                       *Hash
  );

EFI_STATUS
PeiPkcs7Verify (
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI *This,
  IN CONST UINT8 *P7Data,
  IN UINTN        P7Size,
  IN CONST UINT8 *TrustedCert,
  IN UINTN        CertSize,
  IN OUT UINT8  **Data,
  IN OUT UINTN   *DataSize
  );

EFI_STATUS
PeiVerifySig 
(
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI *This,
  IN PEI_CRYPT_HANDLE          *PublicKey,
  IN PEI_CRYPT_HANDLE          *Hash,
  IN VOID                      *Signature,
  IN UINTN                     SignatureSize,
  IN UINT32                    Flags
);

EFI_STATUS
PeiGetKey 
(
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI *This,
  IN CONST EFI_GUID            *KeyAlgorithm, // reserved to PKPUB_KEY_GUID
  IN PEI_CRYPT_HANDLE          *PublicKey
  );

EFI_STATUS
PeiVerifyKey 
(
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI *This,
  IN CONST EFI_GUID            *KeyAlgorithm, // reserved to PKPUB_KEY_GUID
  IN PEI_CRYPT_HANDLE          *PublicKey
  );

//----------------------------------------------------------------------------
// Crypto Protocol Identifiers
//----------------------------------------------------------------------------
static EFI_GUID gAmiDigitalSignaturePPIGuid = AMI_DIGITAL_SIGNATURE_PPI_GUID;

AMI_CRYPT_DIGITAL_SIGNATURE_PPI  mSigPeiInitPpi = {
  PeiHash,
  PeiVerifyKey,
  PeiVerifySig,
  PeiGetKey,
  PeiPkcs7Verify
};

//static 
EFI_PEI_PPI_DESCRIPTOR mPpiSigListVariable = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gAmiDigitalSignaturePPIGuid,
  &mSigPeiInitPpi
};

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  CryptoGetRawImage
//
// Description:    Loads binary from RAW section of X firwmare volume
//
//
// Output:          Buffer - returns a pointer to allocated memory. Caller
//                          must free it when done.
//                  Size  - returns the size of the binary loaded into the
//                          buffer.
//
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
CryptoGetRawImage (IN EFI_GUID *FileGuid, IN OUT VOID **Buffer, IN OUT UINTN *Size)
{
  EFI_STATUS                    Status;
  EFI_FIRMWARE_VOLUME_HEADER    *pFV;
  UINTN                         FvNum=0;
  EFI_FFS_FILE_HEADER           *ppFile=NULL;
    
  if (!Buffer || !Size)
    return EFI_INVALID_PARAMETER;

  Status = (*gPeiServices)->FfsFindNextVolume (gPeiServices, FvNum, &pFV);
  
  while(TRUE)
    {
      Status = (*gPeiServices)->FfsFindNextFile(gPeiServices, EFI_FV_FILETYPE_ALL, pFV, &ppFile);
      if(Status == EFI_NOT_FOUND)
       {
//         FvNum++;
//         Status = (*gPeiServices)->FfsFindNextVolume (gPeiServices, FvNum, &pFV);
//         if(EFI_ERROR(Status)) return Status;
//         continue;
// !!! the PK Key may only be in FV_BB volume. FvNum=0!!!!
           return Status;
       }

      if(guidcmp(&ppFile->Name, FileGuid)==0) break;
    }

  // hopefully we found the file...now try to read raw data
  // !!! Keys are uncompressed. There is no much reason to run compression on prime numbers anyway
  Status = (*gPeiServices)->FfsFindSectionData(gPeiServices, EFI_SECTION_RAW, ppFile, Buffer);
  if(!EFI_ERROR(Status)) {
    // Size may need to subtract Section hdr size = 28 bytes sizeof(EFI_FFS_FILE_HEADER + EFI_COMMON_SECTION_HEADER)
    *Size = FVFILE_SIZE(ppFile)-sizeof(EFI_FFS_FILE_HEADER)-sizeof(EFI_COMMON_SECTION_HEADER);
  }
PEI_TRACE(((UINTN)TRACE_ALWAYS, gPeiServices, "Find Key Ffs %r addr=%X (%X,%X), size=%d\n", Status, (UINT32)*Buffer, ((UINT8*)*Buffer)[0], ((UINT8*)*Buffer)[1], *Size));

  return Status;  
}

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  PeiHash
//
// Description:    Allows creating a hash of an arbitrary message digest using one or more hash algorithms
//
// Input:
//      This          Pointer to the AMI_CRYPT_DIGITAL_SIGNATURE_PPI instance.
//      HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
//      num_elem      Number of blocks to be passed via next argument:addr[]
//      addr[]        Pointer to array of UINT8* addresses of data blocks to be hashed
//      len           Pointer to array of integers containing length of each block listed by addr[]
//      Hash          Holds the resulting hash computed from the message.
//
// Output:    
//      EFI_SUCCESS           Hash returned successfully.
//      EFI_INVALID_PARAMETER Message or Hash is NULL
//      EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this
//                            driver.
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
PeiHash (
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI      *This,
  IN CONST EFI_GUID               *HashAlgorithm,
  IN UINTN                        num_elem,
  IN CONST UINT8                  *addr[],
  IN CONST UINTN                  *len,
  OUT UINT8                       *Hash
  )
{
    BOOLEAN     bSha1 = FALSE, bSha256 = FALSE;
    UINT32      HashLen=SHA256_DIGEST_SIZE;

// Support only SHA1 & SHA256 hashes
    if(!guidcmp((EFI_GUID*)HashAlgorithm, &gEfiHashAlgorithmSha1Guid))
    {
        bSha1 = TRUE;
        HashLen = SHA1_DIGEST_SIZE;
    }
    else 
        if(!guidcmp((EFI_GUID*)HashAlgorithm, &gEfiHashAlgorithmSha256Guid))
        {
            bSha256 = TRUE;
            HashLen = SHA256_DIGEST_SIZE;
        }
         else
            return EFI_UNSUPPORTED;

    MemSet(Hash, HashLen, 0);
    if(bSha1)
        sha1_vector(num_elem, addr, len, Hash);
    else
        sha256_vector(num_elem, addr, len, Hash);


    return  EFI_SUCCESS;
}

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  PeiVerifySig
//
// Description:    Function verifies that the specified signature matches the specified hash. 
//    This function decrypts the signature with the provided key and then compares 
//    the decrypted value to the specified hash value
//
//  Input:
//    This          Pointer to the AMI_CRYPT_DIGITAL_SIGNATURE_PPI instance.
//    PublicKey     Handle to a key used for verifying signatures. This handle must be identifying a public key.
//    Hash          Handle of the hash object to verify.
//    Signature     Pointer to the signature data to be verified.
//    SignatureSize The size, in bytes, of the signature data.
//    Flags         Specifies additional flags to further customize the signing/verifying behavior.
//
// Output:    
//    EFI_SUCCESS               The signature is successfully verified.
//    EFI_SECURITY_VIOLATION    The signature does not match the given message.
//    EFI_ACCESS_DENIED         The key could not be used in signature operation.
//    EFI_INVALID_PARAMETER     The size of input message or signature does not meet the criteria 
//                              of the underlying signature algorithm.
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
PeiVerifySig 
(
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI      *This,
  IN PEI_CRYPT_HANDLE            *PublicKey,
  IN PEI_CRYPT_HANDLE            *Hash,
  IN VOID                        *Signature,
  IN UINTN                       SignatureSize,
  IN UINT32                      Flags
  )
{
    EFI_STATUS      Status;
    INTN            err;
    struct          crypto_rsa_key *key = NULL;
    UINT16          Size = (UINT16)(PublicKey->BlobSize);
    size_t         *sig_len=(size_t*)&SignatureSize;
    INT32           modulus_bitlen = DEFAULT_RSA_SIG_LEN << 3;
    UINT32          HashLen;

// Only supporting RSASSA_PKCS1V15 signature types
    if(!((Flags & EFI_CRYPT_RSASSA_PKCS1V15) || 
         (Flags & EFI_CRYPT_RSASSA_PSS)) )
            return EFI_INVALID_PARAMETER;

    ResetCRmm();

// check Key handle if requested PubKey is a Platform FW Key
// In this case use the FW key from ffs image
// validity of the Key must be verified prior to calling VerifySig
// Guid must match one of the valid keys we can use in PEI Sig verification.
// For now Public Key is supported in 2 formats: RAW 256 bytes and ASN.1 Integer
// shall be extended to gPBkey_x509_Guid
    if(!guidcmp(&PublicKey->AlgGuid, &gEfiCertRsa2048Guid))
        key = crypto_import_rsa2048_public_key(PublicKey->Blob, Size, (UINT8*)&KeyE, LenE);
    else
        return EFI_INVALID_PARAMETER;

    if(!guidcmp(&Hash->AlgGuid, &gEfiHashAlgorithmSha256Guid))
        HashLen = SHA256_DIGEST_SIZE;
    else if(!guidcmp(&Hash->AlgGuid, &gEfiHashAlgorithmSha1Guid))
            HashLen = SHA1_DIGEST_SIZE;
        else
            HashLen = SHA256_DIGEST_SIZE;

    if(key == NULL )
        err = -1;
    else
        err = crypto_rsa_exptmod((const UINT8*)Signature, (size_t)SignatureSize, (UINT8*)&DecriptedSig, sig_len, key, 0);
// locate Hash inside the decrypted signature body and compare it with given Hash;
// Should be extended to handle sha1, sha256 hashes. use Hash->AlgGuid to determine the Hash type
    if(!err) 
    {
        if(Flags & EFI_CRYPT_RSASSA_PKCS1V15)
        {
            // Validate PKCS#1v1.5 Padding
//            err = pkcs_1_v1_5_decode(Hash->Blob, HashLen, (const UINT8 *)&DecriptedSig, (unsigned long)*sig_len);
// just compare the hash at the end of the sig blob
            err = MemCmp(Hash->Blob, (void*)((UINT32)DecriptedSig + (UINT32)(*sig_len - HashLen)), HashLen);
        } else //(Flags & EFI_CRYPT_RSASSA_PSS))
            // Validate PKCS#1 PSS Signature: padding & hash
            err = pkcs_1_pss_decode(
                    Hash->Blob, HashLen, 
                    (const unsigned char *)&DecriptedSig, (unsigned long)*sig_len, 
                    saltlen,  modulus_bitlen);
    }

    Status = !err ? EFI_SUCCESS:EFI_SECURITY_VIOLATION;

// Security concern, memory heap is being cleared on exit 
    ResetCRmm();

    return Status;
}

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  PeiPkcs7Verify
//
// Description:    Verifies the validity of a PKCS#7 signed data as described in "PKCS #7: Cryptographic
//                 Message Syntax Standard".
//                 Function verifies validity of the signature contained inside the Certificate
//                 This function decrypts the signature with the Public key from the Signer certificate 
//                 and then compares the decrypted value to the input Data
//
//  Input:
//      This         Pointer to the AMI_CRYPT_DIGITAL_SIGNATURE_PPI instance.
//      P7Data       Pointer to the PKCS#7 DER encoded message to verify.
//      P7Size       Size of the PKCS#7 message in bytes.
//      TrustedCert  Pointer to a trusted/root X509 certificate encoded in DER, which
//                   is used for certificate chain verification.
//      CertSize     Size of the trusted certificate in bytes.
//      Data         Pointer to the content to be verified/returned at
//      DataSize     Size of Data in bytes
//
// Output:    
//    EFI_SUCCESS              The specified PKCS#7 signed data is valid
//    EFI_SECURITY_VIOLATION   Invalid PKCS#7 signed data.
//    EFI_ACCESS_DENIED        The Trusted certificate does not have a match in SignedData.certificate store.
//    EFI_INVALID_PARAMETER    The size of input message or signature does not meet the criteria 
//                             of the underlying signature algorithm.
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
PeiPkcs7Verify (
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI *This,
  IN CONST UINT8 *P7Data,
  IN UINTN        P7Size,
  IN CONST UINT8 *TrustedCert,
  IN UINTN        CertSize,
  IN OUT UINT8  **Data,
  IN OUT UINTN   *DataSize
  )
{
#if CONFIG_PEI_PKCS7 == 1

    EFI_STATUS  Status;
    INTN        err, reason;
    struct pkcs7_signed_data_st* PKCS7cert;
    struct x509_certificate *x509TrustCert;
    struct x509_certificate *x509SignCert;

    err     = -1;
    reason  = 0;
    x509SignCert = NULL;

    if((*Data == NULL || DataSize == NULL) ||
       (!P7Data || P7Size== 0) || 
       (!TrustedCert || CertSize== 0)
    ) 
        return EFI_INVALID_PARAMETER;

    ResetCRmm();

    PKCS7cert = Pkcs7_parse_Authenticode_certificate(P7Data, P7Size);
    if (PKCS7cert) {
        // verify Pkcs7 Signing Cert chain up to the TrustCert...
        x509TrustCert = x509_certificate_parse(TrustedCert, CertSize);
        if(x509TrustCert) {
            err = Pkcs7_x509_certificate_chain_validate(PKCS7cert, x509TrustCert, (int*)&reason);
            if(!err)
                err = Pkcs7_certificate_validate_digest(PKCS7cert, x509SignCert, *Data, *DataSize);
        }
    } 

    // Security concern, memory heap is being cleared on exit 
    ResetCRmm();

    // failed to process
    Status = !err ? EFI_SUCCESS:EFI_SECURITY_VIOLATION;

    return Status;
#else
    return EFI_UNSUPPORTED;
#endif
}

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  PeiGetKey
//
// Description:    Function returns Ptr to a Platform Signing Key (PK) Ffs 
//                 inside Recovery FV (FV_BB or similar)
//
//  Input:
//    This            Pointer to the AMI_CRYPT_DIGITAL_SIGNATURE_PPI instance.
//    KeyAlgorithm    Points to the EFI_GUID which identifies the PKpub algorithm to use.
//    PublicKey       Handle to a key used to return a ptr to a Key. This handle must be identifying a public key.
//
// Output:
//    EFI_SUCCESS               The Key is successfully returned.
//    EFI_NOT_FOUND             The Key not found
//    EFI_ACCESS_DENIED         The key could not be used in signature operation.
//    EFI_INVALID_PARAMETER     The size of input message or signature does not meet the criteria 
//                              of the underlying signature algorithm.
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
PeiGetKey (
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI      *This,
  IN CONST EFI_GUID          *KeyAlgorithm, // reserved to PKPUB_KEY_GUID
  IN PEI_CRYPT_HANDLE        *PublicKey
  )
{
    if(!PublicKey || !KeyAlgorithm)
        return EFI_INVALID_PARAMETER;

    // now only supporting PKpub key comparison
    if(guidcmp((EFI_GUID*)KeyAlgorithm, &gPKeyGuid))
        return EFI_INVALID_PARAMETER;

    if(pFwKeyHob) {
        PublicKey->AlgGuid = pFwKeyHob->KeyGuid;
        PublicKey->Blob = (UINT8*)pFwKeyHob->KeyAddress;
        PublicKey->BlobSize = pFwKeyHob->KeySize;
        return EFI_SUCCESS;
    }

    return EFI_NOT_FOUND;
}

//**********************************************************************
//<AMI_PHDR_START>
//
// Procedure:  PeiVerifyKey
//
// Description:    Function compares the input PublicKey against 
//                 Platform Signing Key (PK) image in the flash.
//
//  Input:
//    This            Pointer to the AMI_CRYPT_DIGITAL_SIGNATURE_PPI instance.
//    KeyAlgorithm    Points to the EFI_GUID which identifies the PKpub algorithm to use.
//    PublicKey       Handle to a key used for verifying signatures.  This handle must be identifying a public key.
//
// Output:
//    EFI_SUCCESS               The Key is successfully verified.
//    EFI_SECURITY_VIOLATION    The Key does not match current FW key.
//    EFI_ACCESS_DENIED         The key could not be used in signature operation.
//    EFI_INVALID_PARAMETER     The size of input message or signature does not meet the criteria 
//                              of the underlying signature algorithm.
//<AMI_PHDR_END>
//**********************************************************************
EFI_STATUS
PeiVerifyKey 
(
  IN CONST AMI_CRYPT_DIGITAL_SIGNATURE_PPI      *This,
  IN CONST EFI_GUID          *KeyAlgorithm, // reserved to PKPUB_KEY_GUID
  IN PEI_CRYPT_HANDLE        *PublicKey
  )
{
    EFI_STATUS    Status;
    int           err;
    PEI_CRYPT_HANDLE KeyHndl;
    UINT8         Hash[SHA256_DIGEST_SIZE] = {0};
    UINT8         *KeyBuf, *PKpubBuffer=NULL;
    UINT32        KeyLen;

    if(!PublicKey || !KeyAlgorithm || !PublicKey->Blob)
        return EFI_INVALID_PARAMETER;
// check Key handle if requested PubKey is a Platform Key PKpub.
// In this case use PKpub key from ffs image
    if(guidcmp((EFI_GUID*)KeyAlgorithm, &gPKeyGuid))
        return EFI_INVALID_PARAMETER;

    Status = PeiGetKey(This, KeyAlgorithm, &KeyHndl);
    if(!EFI_ERROR(Status)) {
// only store Sha256 or n-modulus of RSA2048. For x509 cert - compare hash of an entire cert
// FFS - Sha256 Hash ->
//       Input =Sha258  -> cmp
//       Input =RSA2048 -> Hash n-modulus
//       Input =x509    -> Hash x509 cert
// FFS - RSA2048 ->
//       Input =RSA2048 -> cmp
//       Input =x509    -> extract n-modulus
// FFS - x5098 ->
//       Input =x509    -> cmp
/*
        PKpubBuffer = KeyHndl.Blob;
        KeyLen = KeyHndl.BlobSize; // always 256
        KeyBuf = PublicKey->Blob;

        if(!guidcmp(&KeyHndl.AlgGuid, &gEfiCertSha256Guid)) {
            KeyBuf = Hash;
            KeyLen = SHA256_DIGEST_SIZE;
            if(!guidcmp(&PublicKey->AlgGuid, &gEfiCertRsa2048Guid) ||
               !guidcmp(&PublicKey->AlgGuid, &gEfiCertX509Guid) ) {
            // SHA256 Hash of RSA Key/x509 cert
                sha256_vector(1, (const UINT8**)&PublicKey->Blob, (const UINTN*)&PublicKey->BlobSize, Hash);
            }
        } else 
            // if FwKey is x509 and Key->Algo - gEfiCertRsa2048Guid:
            // derive nModulus from x509 Key Cert for comparison
            if(!guidcmp(&KeyHndl.AlgGuid, &gEfiCertRsa2048Guid) &&
               !guidcmp(&PublicKey->AlgGuid, &gEfiCertX509Guid) ) {
                PKpubBuffer = &Hash[0];
                KeyLen = DEFAULT_RSA_KEY_MODULUS_LEN;
                ResetCRmm();
                err = Pkcs7_x509_return_Cert_pubKey((UINT8*)PublicKey->Blob, (UINTN)PublicKey->BlobSize, &PKpubBuffer, &KeyLen);
                ResetCRmm();
                if(err) return EFI_SECURITY_VIOLATION;
            }
*/
        PKpubBuffer = KeyHndl.Blob;
        KeyLen = KeyHndl.BlobSize; // always 256
        KeyBuf = PublicKey->Blob;
        if(!guidcmp(&KeyHndl.AlgGuid, &gEfiCertSha256Guid) &&
           !guidcmp(&PublicKey->AlgGuid, &gEfiCertRsa2048Guid)
        ) {
        // SHA256 Hash of RSA Key
            KeyLen = SHA256_DIGEST_SIZE;
            KeyBuf = Hash;
            sha256_vector(1, (const UINT8**)&PublicKey->Blob, (const UINTN*)&PublicKey->BlobSize, KeyBuf);
#if CONFIG_PEI_PKCS7 == 1
        } else {
            // if FwKey is x509 and Key->Algo - gEfiCertRsa2048Guid:
            // derive nModulus from x509 Key Cert for comparison
            if(!guidcmp(&KeyHndl.AlgGuid, &gEfiCertRsa2048Guid) &&
               !guidcmp(&PublicKey->AlgGuid, &gEfiCertX509Guid)
            ) {
                PKpubBuffer = &Hash[0];
                KeyLen = DEFAULT_RSA_KEY_MODULUS_LEN;
                ResetCRmm();
                err = Pkcs7_x509_return_Cert_pubKey((UINT8*)PublicKey->Blob, (UINTN)PublicKey->BlobSize, &PKpubBuffer, &KeyLen);
                ResetCRmm();
                if(err) return EFI_SECURITY_VIOLATION;
            }
#endif
        }

        err = MemCmp(PKpubBuffer, KeyBuf, KeyLen);
        Status = !err ? EFI_SUCCESS:EFI_SECURITY_VIOLATION;

    }

    return Status;
}

//<AMI_PHDR_START>
//----------------------------------------------------------------------------
// Procedure:   CryptoPei_Init
//
// Description: This function is the entry point for this PEI.
//
//
// Input:       FfsHeader   Pointer to the FFS file header
//              PeiServices Pointer to the PEI services table
//
// Output:      Return Status based on errors that occurred while waiting for
//              time to expire.
//----------------------------------------------------------------------------
//<AMI_PHDR_END>
EFI_STATUS
CryptoPei_Init (
  IN EFI_FFS_FILE_HEADER       *FfsHeader,
  IN EFI_PEI_SERVICES          **PeiServices
)
{
    EFI_STATUS              Status;
    UINTN                   Size;
    UINTN                   Npages;
    EFI_PHYSICAL_ADDRESS    DstAddress;
    EFI_BOOT_MODE           BootMode;
    UINT8         Index;
    UINT8        *pBuf;

    gPeiServices = PeiServices; 

    Status = (*gPeiServices)->GetBootMode( PeiServices, &BootMode );
    if(EFI_ERROR(Status) || BootMode == BOOT_ON_S3_RESUME) {
        return Status; // skip Crypto PPI install on S3 resume
    }

////////////////////////////////////////////////////////////////////////////////////
//
// Create FwKey Hob
//
////////////////////////////////////////////////////////////////////////////////////
    Index = 0;
    while(gKeyFileGuid[Index] != NULL)
    {
// Available Key Cert GUIDs: RSA2048, SHA256 and x509
        Status = CryptoGetRawImage(gKeyFileGuid[Index], (VOID**)&pBuf, (UINTN*)&Size);
        if(!EFI_ERROR(Status)) {
        //  make sure the Key buffer is mapped to FV_BB address space 
/*
            if(!((UINT32)pBuf > FV_BB_BASE && 
                 (UINT64)((UINT32)pBuf+Size) < 
                 (UINT64)(FV_BB_BASE+(UINT64)FV_BB_BLOCKS*FLASH_BLOCK_SIZE)))
                break;
*/
            Status = (*PeiServices)->CreateHob(
                PeiServices, EFI_HOB_TYPE_GUID_EXTENSION, 
               sizeof(FW_KEY_HOB), &pFwKeyHob);
            if (!EFI_ERROR(Status) && pFwKeyHob) {
                pFwKeyHob->Header.Name = gPKeyGuid;
                pFwKeyHob->KeyGuid =  *gKeyTypeGuid[Index];
                pFwKeyHob->KeyAddress = (EFI_PHYSICAL_ADDRESS)(UINT32)pBuf;
                pFwKeyHob->KeySize = Size;
            }    
            break;
        }
        Index++;
    }

////////////////////////////////////////////////////////////////////////////////////
//
// Init Aux Memory Manager
//
////////////////////////////////////////////////////////////////////////////////////
// convert the Heap Size in bytes to the number of pages and allocate appropriate number of pages

    Size = CR_PEI_MAX_HEAP_SIZE;
    Npages = EFI_SIZE_TO_PAGES(Size);
    Status = (*gPeiServices)->AllocatePages(gPeiServices, EfiBootServicesData, Npages, &DstAddress);
    PEI_TRACE(((UINTN)TRACE_ALWAYS, gPeiServices, "Heap alloc %r (addr=%X, size=%d)\n", Status, (UINT32)DstAddress, Size));
    if(EFI_ERROR(Status))
    {
        return Status;
    }
    InitCRmm((void*)DstAddress, Size);
    //  
    // Update Crypto debug traces level
    //
    wpa_set_trace_level(CRYPTO_trace_level); 

////////////////////////////////////////////////////////////////////////////////////
//
// Install VerifySig PPI
//
////////////////////////////////////////////////////////////////////////////////////
    return (**gPeiServices).InstallPpi (gPeiServices, &mPpiSigListVariable);
}

//**********************************************************************
//**********************************************************************
//**                                                                  **
//**        (C)Copyright 1985-2013, American Megatrends, Inc.         **
//**                                                                  **
//**                       All Rights Reserved.                       **
//**                                                                  **
//**        5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093         **
//**                                                                  **
//**                       Phone: (770)-246-8600                      **
//**                                                                  **
//**********************************************************************
//**********************************************************************