diff options
Diffstat (limited to 'Core/EM/CryptoPkg/CryptoPei.c')
-rw-r--r-- | Core/EM/CryptoPkg/CryptoPei.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/Core/EM/CryptoPkg/CryptoPei.c b/Core/EM/CryptoPkg/CryptoPei.c new file mode 100644 index 0000000..1945986 --- /dev/null +++ b/Core/EM/CryptoPkg/CryptoPei.c @@ -0,0 +1,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 ** +//** ** +//********************************************************************** +//********************************************************************** |