diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/CryptoPkg/CryptoDxe.c | |
download | zprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz |
Diffstat (limited to 'Core/EM/CryptoPkg/CryptoDxe.c')
-rw-r--r-- | Core/EM/CryptoPkg/CryptoDxe.c | 1108 |
1 files changed, 1108 insertions, 0 deletions
diff --git a/Core/EM/CryptoPkg/CryptoDxe.c b/Core/EM/CryptoPkg/CryptoDxe.c new file mode 100644 index 0000000..8c40af1 --- /dev/null +++ b/Core/EM/CryptoPkg/CryptoDxe.c @@ -0,0 +1,1108 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/CryptoDxe.c 31 8/15/13 9:43a Alexp $ +// +// $Revision: 31 $ +// +// $Date: 8/15/13 9:43a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/BIN/Modules/CryptoPkg/CryptoDxe.c $ +// +// 31 8/15/13 9:43a Alexp +// Pkcs7Verify() - add TimeStamp signature processing(UEFI ECR1009) +// Pkcs7Verify() - enable code branch for PKCS7_MUTEX_LOCK +// +// 30 8/02/13 4:26p Alexp +// Moved EFI_HASH_ALGORITHM_SHA256_NOPAD_GUID under AmiDigSig +// Protocol defining header file +// +// 29 8/02/13 4:00p Alexp +// 1. Fix logic to get FwKey from a Hob. +// Key is copied into pre-allocated buffer by driver entry point +// 2. Optimized Pkcs7Verify. +// +// 27 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 +// +// 26 1/11/13 10:07a Alexp +// GetKey(): fix MemCpy() 2nd argument. Was not copying a key buffer. +// +// 25 12/28/12 2:50p Alexp +// EIP#110823:The system cannot boot to UEFI(WIN8) OS if the Secure Flash +// Pkg module is not supported +// Update GetKey(); InSmmFunction() and NotInSmmFunction() routines +// to handle cases when Fw Key FFS file not present +// +// 23 12/10/12 6:09p Alexp +// Bug fix: InSmmFunction() the Key pointer gKeyBuf was to updated to Key +// in SMM region +// +// 21 12/07/12 4:08p Alexp +// disable debug crypto traces in SMM +// +// 20 11/29/12 3:10p Alexp +// Pkcs7Verify()- +// Fix error checking for input **Data parameter : Data == NULL +// +// 18 11/16/12 5:10p Alexp +// EIP#105015: Add handling of x509 format for Platform FW Key in FFS +// files +// +// 16 8/28/12 12:33p Alexp +// UEFI 2.3.1. ErrataC. +// Added support for new Hash types +// defined by a GUID with 'NOPAD' keyword: +// EFI_HASH_ALGORITHM_SHA1_NOPAD_GUID +// EFI_HASH_ALGORITHM_SHA256_NOPAD_GUID +// +// 15 8/22/12 4:28p Alexp +// Added support in Pkcs7Parse() for new operations: +// Pkcs7CertValidateGetSignerKey - n-modulus of Signer key +// Pkcs7CertGetMatchInCertChain - true if found leaf cert matching +// to +// trust cert +// Pkcs7CertValidateGetCAKey, - n-modulus of CA key if detected +// in +// x509 chain +// Pkcs7GetCAKey, Pkcs7GetSignerKey +// +// 12 7/23/12 4:12p Alexp +// Pkcs7Verify: +// Bug Fix. For condition:Pkcs7CertValidateGetMatchInCertChain return +// success if leaf cert is found. Before code fell down testing +// certificate and could return error potentially misleading Caller of this +// function. +// +// 11 7/18/12 8:57p Alexp +// Pkcs7Verify +// fix bug - "reason" var was used uninitialized +// +// 10 5/04/12 9:49a Alexp +// [TAG] EIP89280 +// [Category] Improvement +// [Description] When secure boot enable with secure flash disable, in +// Security page of setup menu same items will exist twice +// Fix: Install Crypto Protocols even if Root FW Key not found (brought in +// by Sec Flash module) +// [Files] cryptoDxe.c +// +// 9 4/11/12 5:27p Alexp +// Add new operand within Pkcs7Validate: +// Pkcs7CertValidateGetMatchInCertChain +// +// 7 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 +// +// 6 2/29/12 4:04p Alexp +// 1. Add VerifyKey +// 2. Fix GetKey (API call will be deprecated as not needed) to move PR +// Key from file to local storage +// 3. Use FWKEY_FORMAT to process VerifyKey according to file format. Hash +// input RSA2048 key for comparison if PR Key stored as Hash +// +// 5 11/14/11 12:01p Alexp +// InSmmFunction()->InstallMultipleProtocols() Change the HAndle argument +// from ImageHandle to a DummyHandle=NULL +// +// 4 6/30/11 5:45p Alexp +// GetRawImage: added freepool(HandleBuffer) +// +// 3 6/27/11 5:30p Alexp +// removed commented out lines +// +// 2 6/22/11 5:46p Alexp +// update deafult Crypto trace level +// +// 1 6/13/11 5:19p Alexp +// +// 7 6/10/11 6:21p Alexp +// added new Pkcs7 parse Operation: Pkcs7CertValidateGetSignerKeyHash +// +// 6 6/09/11 9:57a Alexp +// always parse PKCS7 cert +// +// 5 5/18/11 1:18p Alexp +// edited text in func headers +// +// 4 5/17/11 12:53p Alexp +// fix WDK Level4 compiler warnings +// +// 3 5/11/11 7:38p Alexp +// remove set trace level call. If needed, modify Sdl token in Crypto Src +// +// 2 5/10/11 6:55p Alexp +// use external Guid variable declarations +// +// 1 5/06/11 6:11p Alexp +// initial module release +// +// 10 4/22/11 4:20p Alexp +// cleaned up CryptoGetRawImage +// +// 9 4/18/11 7:09p Alexp +// +// 8 4/11/11 12:52p Alexp +// remove ASN1 as possible Key buf format. +// +// 7 4/05/11 6:31p Alexp +// remove content from GetKey. We may add get FwSig key in later +// revisions +// +// 6 3/31/11 6:14p Alexp +// hashing of SpcIndirect data is done inside Pkcs Validate +// +// +//********************************************************************** +#include <Token.h> +#include <AmiDxeLib.h> +#include "Setup.h" +#include "AmiCertificate.h" +#include <Protocol\AmiDigitalSignature.h> +#include <Protocol\Hash.h> + +#include <cryptlib.h> + +#include <Protocol\SmmBase.h> // used for SMM Malloc + +// +// Global variables +// +extern EFI_BOOT_SERVICES *pBS; +extern EFI_RUNTIME_SERVICES *pRS; + +static EFI_GUID gPRKeyGuid = PR_KEY_GUID; + +// The ptr to a buffer containing the Fw Platform Key +// Key Image is copied from .ffs to a local buffer. +// It is a safe location in case of AmiSig running in SMM +static CRYPT_HANDLE gKey = {{0},0,NULL}; + +// Second part of the Public key, public exponent (e), +// must be hardwired in the FW elsewhere(recommended value of e=65537). +// +// SDL Hardwired value of publicExponent--e +const UINT8 KeyE[] = {E_CONST}; // 0x10001 +const UINT32 LenE = sizeof(KeyE); +const INT32 saltlen = PSS_SIG_SALTLEN; // 8 +static UINT8 Rsa2048Sig[DEFAULT_RSA_SIG_LEN]; + +// Pkcs7 Certificate private var +//struct pkcs7_signed_data_st* PKCS7cert = NULL; +// Mutex to control Memory reset during atomic Pkcs7 operations +static UINT8 MutexLock = RESET; + +//---------------------------------------------------------------------------- +// Crypto Function prototypes +//---------------------------------------------------------------------------- +EFI_STATUS +Pkcs1Verify ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN CRYPT_HANDLE *PublicKey, + IN CRYPT_HANDLE *Hash, + IN VOID *Signature, + IN UINTN SignatureSize, + IN UINT32 Flags + ); + +EFI_STATUS +Pkcs7Verify ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN CONST UINT8 *P7Data, + IN UINTN P7Size, + IN CONST UINT8 *TrustedCert, + IN UINTN CertSize, + IN OUT UINT8 **Data, + IN OUT UINTN *DataSize, + IN UINT8 Operation, + IN UINT32 Flags + ); + +EFI_STATUS +Hash( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN CONST EFI_GUID *HashAlgorithm, + IN UINTN Num_elem, + IN CONST UINT8 *Addr[], + IN CONST UINTN *Len, + OUT UINT8 *Hash + ); + +EFI_STATUS +GetKey ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + OUT CRYPT_HANDLE *Key, + IN EFI_GUID *AlgId, + IN UINTN KeyLen, + IN UINT32 Flags + ); + +EFI_STATUS +VerifyKey ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN EFI_GUID *AlgId, + IN CRYPT_HANDLE *Key + ); +//---------------------------------------------------------------------------- +// Crypto Protocol Identifiers +//---------------------------------------------------------------------------- +AMI_DIGITAL_SIGNATURE_PROTOCOL mAmiSig = { + Pkcs1Verify, + Pkcs7Verify, + Hash, + GetKey, + VerifyKey +}; + +//---------------------------------------------------------------------------- +// Crypto Function Implementation +//---------------------------------------------------------------------------- + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: Hash +// +// Description: Allows creating a hash of an arbitrary message digest using one or more hash algorithms +// +// Input: +// This Pointer to the AMI_DIGITAL_SIGNATURE_PROTOCOL 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 +Hash( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *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) || + !guidcmp((EFI_GUID*)HashAlgorithm, &gEfiHashAlgorithmSha1NoPadGuid)) + { + bSha1 = TRUE; + HashLen = SHA1_DIGEST_SIZE; + } + else + if(!guidcmp((EFI_GUID*)HashAlgorithm, &gEfiHashAlgorithmSha256Guid) || + !guidcmp((EFI_GUID*)HashAlgorithm, &gEfiHashAlgorithmSha256NoPadGuid)) + { + 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: Pkcs7Verify +// +// Description: Verifies the validity of a PKCS#7 signed data as described in "PKCS #7: Cryptographic +// Message Syntax Standard". +// Function perfors several operations on input Pkcs7 certificate +// based on the input Operation argument +// 1. 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 +// 2. Extracts the Signer certificate in format of x509 +// 3. Extracts Root CA certificate that used to sign the Signer certificate. +// +// Input: +// This Pointer to the AMI_DIGITAL_SIGNATURE_PROTOCOL 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 +// Operation Specifies different tasks to perform: +// 0-Function presence check. Must return EFI_SUCCESS +// 1-Validate Certificate +// 2-Return Signer Certificate in *Data. Performs cert chaining and time based validity tests +// 3-Return Root CA certificate referenced by Signer. Used to compare with Trusted Cert in FW +// 4-Validate Root Certificate +// 5-Validate Signer Certificate Chain +// 6-Return Signature Digest Algorithm +// 7-Validate Certificate, return Root CA Certificate +// 8-Validate Certificate, return Signer Certificate +// 9-Validate Certificate, return Signer Key Hash (SHA256) +// 10-Validate Certificate and return Success if match is found between Trust and any leaf certificates in the Signer chain +// 11-Validate Certificate, return ptr in *Data to n-modulus of a Signer Key +// 12-Return Success if match is found between Trust and any leaf certificates in the Signer chain +// 13-Validate Certificate, return ptr in *Data to n-modulus of a Root CA Key +// 14-Return ptr in *Data to n-modulus of a Root CA Key +// 15-Return ptr in *Data to n-modulus of a Signer Key +// 16-Validate TimeStamp certificate chain in Pkcs7 Certificate +// 17-255 reserved values +// Flags Specifies additional flags to further customize the signing/verifying behavior. +// +// 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 +Pkcs7Verify ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN CONST UINT8 *P7Data, + IN UINTN P7Size, + IN CONST UINT8 *TrustedCert, + IN UINTN CertSize, + IN OUT UINT8 **Data, + IN OUT UINTN *DataSize, + IN UINT8 Operation, + IN UINT32 Flags + ) +{ + EFI_STATUS Status; + INTN err, reason; + static struct pkcs7_signed_data_st* PKCS7cert; + struct x509_certificate *x509SignCert; + struct x509_certificate *x509TrustCert; + UINT8 *x509SignCertPtr, *x509RootCertPtr; + UINTN SignCert_len, CARootCert_len; + struct pkcs7_cert_revoke_info revokeInfo; + EFI_CERT_X509_SHA256 *revokeCert; + +// Mutex functionality: +/* +Structure mutex +Mutual exclusion (mutex) semaphore locking mechanism used to serialise interthread intraprocess activities. +*/ +#if PKCS7_MUTEX_LOCK == 1 + switch(Flags & 0x3) { + case RESET: + ResetCRmm(); // first time needs mem clean + MutexLock = RESET; + PKCS7cert = NULL; + break; + + case LOCK: + ResetCRmm(); // first time needs mem clean + MutexLock = LOCK; + PKCS7cert = NULL; + break; + + case RELEASE: // clear memory after execute routines + if(MutexLock == RESET) + ResetCRmm(); + MutexLock = RESET; + break; + + case KEEP: + if(MutexLock == RESET) + ResetCRmm(); + break; + + default: + ResetCRmm(); + } +#else + PKCS7cert = NULL; + ResetCRmm(); +#endif +/* + Notes of implementation: + + IN order to allocate the Pool for returned Cert (Signer or CA) + -run getCert with Size 0 -> it will return real cert size + -allocate buffer of Size and re-run with new size + OR caller is responsible for freeng the Data buffer + OR caller always allocates sufficient size == Trusted Cert + 1k + + GetSignerCert + parse Pkcs7 to *Pkcs7cert + get SignerName from SignerInfo.serialName + find x509 cert matching Signer name + GetCACert + run GetSignerCert + run cert chain valid for that cert + + ValidateSignCert - internal Cert validation, returns Root CA Cert ptr + ValidateTrustCert - external Trust Cert validation, returns Sign Cert ptr + +*/ + err = -1; + reason=0; + + switch(Operation){ + case Pkcs7Arg0: + Status = EFI_SUCCESS; + err = 0; + break; +// Validate Digest and returns Root CA cert or Signer Cert + case Pkcs7CertGetMatchInCertChain: + case Pkcs7CertValidateGetMatchInCertChain: // obsolete + reason = -1; // non-0 reason argument forces Pkcs7_Chain_Validate to scan for matching Cert in the Chain if other checks failed + case Pkcs7CertValidate: + case Pkcs7CertValidateGetCAKey: + case Pkcs7CertValidateGetCACert: + case Pkcs7CertValidateGetSignerKey: + case Pkcs7CertValidateGetSignerCert: + case Pkcs7CertValidateGetSignerKeyHash: + case Pkcs7TimeStampCertValidateGet: + if(Data == NULL || DataSize == NULL) + break; + case Pkcs7ValidateRootCert: + if (!PKCS7cert) PKCS7cert = Pkcs7_parse_Authenticode_certificate(P7Data, P7Size); + if (!PKCS7cert) + break; + // verify Pkcs7 Signing Cert chain up to the TrustCert...if provided + if(TrustedCert && CertSize) { + x509TrustCert = x509_certificate_parse(TrustedCert, CertSize); + if(x509TrustCert) { + err = Pkcs7_x509_certificate_chain_validate_with_timestamp(PKCS7cert, (Operation == Pkcs7TimeStampCertValidateGet), x509TrustCert, NULL, (int*)&reason); + } else { + // potentially a TimeStamped revocation cert + revokeCert = (EFI_CERT_X509_SHA256*)TrustedCert; + if(CertSize == sizeof(EFI_CERT_X509_SHA256)) + revokeInfo.ToBeSignedHashLen = 32; + else + if(CertSize == sizeof(EFI_CERT_X509_SHA384)) + revokeInfo.ToBeSignedHashLen = 48; + else + if(CertSize == sizeof(EFI_CERT_X509_SHA512)) + revokeInfo.ToBeSignedHashLen = 64; + else { // unsupported Hash struct + err = -1; + break; + } + revokeInfo.ToBeSignedHash = (UINT8*)&revokeCert->ToBeSignedHash; + err = Pkcs7_x509_certificate_chain_validate_with_timestamp(PKCS7cert, FALSE, NULL, &revokeInfo, (int*)DataSize); + } + + if(err == -1 || + Operation==Pkcs7CertGetMatchInCertChain || + Operation == Pkcs7ValidateRootCert + ) + break; // break(err=0) if leaf found to match trust cert + } + // x509SignCert== NULL -> extract SignCert from Pkcs7 crt + err = Pkcs7_certificate_validate_digest(PKCS7cert, NULL, (UINT8*)*Data, (UINTN)*DataSize); + if(!err) { + switch(Operation){ + //Returns CA Root cert after successfully validating Cert chain and signature digest + case Pkcs7CertValidateGetCACert: + err = Pkcs7_return_cerificate_ptr(PKCS7cert, Data, DataSize, &x509SignCertPtr, (size_t*)&SignCert_len); + break; + //Returns Signing Key from Cert after successfully validating Cert chain and signature digest + case Pkcs7CertValidateGetSignerCert: + err = Pkcs7_return_cerificate_ptr(PKCS7cert, &x509RootCertPtr, (size_t*)&CARootCert_len, Data, DataSize); + break; + case Pkcs7CertValidateGetSignerKeyHash: + err = Pkcs7_x509_return_signing_Key(PKCS7cert, &x509SignCertPtr, &SignCert_len); + if(!err) { + Hash(This, &gEfiHashAlgorithmSha256Guid, 1, &x509SignCertPtr, (const UINTN*)&SignCert_len, *Data); + *DataSize=SHA256_DIGEST_SIZE; + } + break; + case Pkcs7CertValidateGetSignerKey: + err = Pkcs7_x509_return_signing_Key(PKCS7cert, Data, DataSize); + break; + case Pkcs7CertValidateGetCAKey: + err = Pkcs7_return_cerificate_ptr(PKCS7cert, Data, DataSize, &x509SignCertPtr, (size_t*)&SignCert_len); + if(!err) + err = Pkcs7_x509_return_Cert_pubKey(*Data, *DataSize, Data, DataSize); + break; + case Pkcs7TimeStampCertValidateGet: + err = Pkcs7_certificate_validate_timestamp_digest(PKCS7cert, (long*)DataSize); + break; + } + } + break; + +// returns Ptr within input P7Data DER buffer to RootCA cert or Signing Cert + case Pkcs7GetSignerCert: + case Pkcs7GetCACert: + case Pkcs7GetSignerKey: + case Pkcs7GetCAKey: + if(Data == NULL || DataSize == NULL) { + break; + } + if (!PKCS7cert) PKCS7cert = Pkcs7_parse_Authenticode_certificate(P7Data, P7Size); + if (PKCS7cert) { + err = Pkcs7_return_cerificate_ptr(PKCS7cert, &x509RootCertPtr, (size_t*)&CARootCert_len, &x509SignCertPtr, (size_t*)&SignCert_len); + if(!err) { + switch(Operation){ + case Pkcs7GetSignerCert: + *DataSize = SignCert_len; + *Data = x509SignCertPtr; + break; + case Pkcs7GetCACert: + *DataSize = CARootCert_len; + *Data = x509RootCertPtr; + break; + case Pkcs7GetCAKey: + err = Pkcs7_x509_return_Cert_pubKey(x509RootCertPtr, CARootCert_len, Data, DataSize); + break; + case Pkcs7GetSignerKey: + err = Pkcs7_x509_return_Cert_pubKey(x509SignCertPtr, SignCert_len, Data, DataSize); + break; + } + } + } + break; + + case x509ValidateCertChain: + //Validates Signer certificate's key against Trusted Cert + x509SignCert = x509_certificate_parse(P7Data, P7Size); + if(TrustedCert && CertSize) + x509TrustCert = x509_certificate_parse(TrustedCert, CertSize); + if (x509TrustCert && x509SignCert) + err = x509_certificate_chain_validate(x509TrustCert, x509SignCert, (int*)&reason); + break; + + case Pkcs7GetDigestAlgorithm: + // validate input params. + if(Data == NULL || DataSize == NULL) { + break; + } + if (!PKCS7cert) PKCS7cert = Pkcs7_parse_Authenticode_certificate(P7Data, P7Size); + if (PKCS7cert) { + err = Pkcs7_return_digestAlgorithm(PKCS7cert, (UINT8*)*Data); + if(!err) + *DataSize = sizeof(UINT8); + } + break; + + default: + Status = EFI_INVALID_PARAMETER; + err = -1; + } + +// Security concern, memory heap is being cleared on exit + if(err) + MutexLock = RESET; + +#if PKCS7_MUTEX_LOCK == 1 + if(MutexLock == RESET) +#endif + { + ResetCRmm(); + PKCS7cert = NULL; + } + +// failed to process + Status = !err ? EFI_SUCCESS:EFI_SECURITY_VIOLATION; + + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: Pkcs1Verify +// +// Description: Function verifies that the specified signature matches the specified hash. +// Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in +// RSA PKCS#1. +// 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_DIGITAL_SIGNATURE_PROTOCOL 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 +Pkcs1Verify ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN CRYPT_HANDLE *PublicKey, + IN 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 & PSS signature types + if(!((Flags & EFI_CRYPT_RSASSA_PKCS1V15) || + (Flags & EFI_CRYPT_RSASSA_PSS)) ) + return EFI_INVALID_PARAMETER; + + if(!PublicKey || !Hash || !Signature) + return EFI_INVALID_PARAMETER; + + ResetCRmm(); + MutexLock = RESET; + +// For now Public Key is supported in 2 formats: RAW 256 bytes and ASN.1 Integer + if(!guidcmp(&PublicKey->AlgGuid, &gEfiCertRsa2048Guid)) + key = crypto_import_rsa2048_public_key(PublicKey->Blob, Size, (UINT8*)&KeyE, LenE); + else + return EFI_INVALID_PARAMETER; + +// 2 hash types supporte: SHA1 & SHA256 + 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*)&Rsa2048Sig, sig_len, key, 0); + +// locate Hash inside the decrypted signature body and compare it with given Hash; + if(!err) { + if(Flags & EFI_CRYPT_RSASSA_PKCS1V15) + { + // Validate PKCS#1 Padding +// err = pkcs_1_v1_5_decode((const UINT8 *)&Hash->Blob, HashLen, (const UINT8 *)&Rsa2048Sig, (unsigned long)*sig_len); + err = MemCmp((void*)(UINTN)Hash->Blob, (void*)(UINTN)((UINT32)(UINTN)Rsa2048Sig + (UINT32)(*sig_len - HashLen)), HashLen); + } + else //(Flags & EFI_CRYPT_RSASSA_PSS)) + // Validate PKCS_1 PSS Signature: padding & hash + err = pkcs_1_pss_decode((UINT8*)Hash->Blob, HashLen,(const unsigned char *)&Rsa2048Sig, (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: CryptoGetFwKey +// +// Description: Passes FwKey info from a Hob to an external Key handler structure +// +// Input: Key - ptr to the buffer to hold the target key parameters +// +// Output: Status +// +// EFI_NOT_FOUND - Can't find the Key Hob +// EFI_INVALID_PARAMETER - Wrong KeyID +// EFI_LOAD_ERROR - Load fail. +// EFI_SUCCESS - Load success. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +CryptoGetFwKey ( + IN EFI_SYSTEM_TABLE *SystemTable, + IN CRYPT_HANDLE *Key +) +{ + EFI_STATUS Status=EFI_NOT_FOUND; + FW_KEY_HOB *pFwKeyHob; + static EFI_GUID HobListGuid = HOB_LIST_GUID; + + if(!Key) return EFI_INVALID_PARAMETER; + + pFwKeyHob = GetEfiConfigurationTable(SystemTable, &HobListGuid); + if (pFwKeyHob!=NULL) { + Status = FindNextHobByGuid(&gPRKeyGuid, &pFwKeyHob); + if(!EFI_ERROR(Status)) { +// make sure the Key buffer is mapped to FV_BB address space +/* + if(!((UINT32)pFwKeyHob->KeyAddress > FV_BB_BASE && + (UINT64)((UINT32)pFwKeyHob->KeyAddress+pFwKeyHob->KeySize) < + (UINT64)(FV_BB_BASE+(UINT64)FV_BB_BLOCKS*FLASH_BLOCK_SIZE))) { + return EFI_NOT_FOUND; +*/ + Key->Blob = (UINT8*)(UINT32)pFwKeyHob->KeyAddress; + Key->BlobSize = pFwKeyHob->KeySize; + Key->AlgGuid = pFwKeyHob->KeyGuid; + } + } + + TRACE(((UINTN) -1,"Get Key File %g: %r\n(%lx, %dbytes)=%X,%X\n", Key->AlgGuid, Status, Key->Blob, Key->BlobSize, Key->Blob[0], Key->Blob[1])); + + return Status; +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: GetKey +// +// Description: Return Firmware Signing Key from a local storage +// +// Input: +// This Pointer to the AMI_DIGITAL_SIGNATURE_PROTOCOL instance. +// Key ptr to the buffer to hold the target key +// AlgId Key GUID +// KeyLen Length of the target Key buffer +// Flags Specifies additional flags to further customize the GetKey behavior. +// Output: +// EFI_SUCCESS +// EFI_ACCESS_DENIED The key could not be located +// EFI_INVALID_PARAMETER Wrong KeyID +// BUFFER_TOO_SMALL The Key->BlobSize will contain the size of the buffer to be prepared +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +GetKey ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + OUT CRYPT_HANDLE *Key, + IN EFI_GUID *AlgId, + IN UINTN KeyLen, + IN UINT32 Flags + ) +{ + if(!AlgId || !Key) + return EFI_INVALID_PARAMETER; + +// Guid must match one of the valid keys we can use in Sig verification. + if(guidcmp(AlgId, &gPRKeyGuid)) + return EFI_UNSUPPORTED; + + if(gKey.Blob && gKey.BlobSize){ + +// make sure the Key buffer is mapped to FV_BB address space +/* if(!((UINT32)gKey.Blob > FV_BB_BASE && + (UINT64)((UINT32)gKey.Blob+gKey.BlobSize) < + (UINT64)(FV_BB_BASE+(UINT64)FV_BB_BLOCKS*FLASH_BLOCK_SIZE))) + return EFI_NOT_FOUND; +*/ + Key->BlobSize = gKey.BlobSize; + Key->AlgGuid = gKey.AlgGuid; + if(Key->Blob) { + if(KeyLen < gKey.BlobSize) + return EFI_BUFFER_TOO_SMALL; + else + MemCpy(Key->Blob, gKey.Blob, gKey.BlobSize); + } else + Key->Blob = gKey.Blob;// upd address to int buffer + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: VerifyKey +// +// Description: Function compares the input PublicKey against +// Platform Signing Key (PK) image in the flash. +// +// Input: +// This Pointer to the AMI_DIGITAL_SIGNATURE protocol 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 +VerifyKey ( + IN CONST AMI_DIGITAL_SIGNATURE_PROTOCOL *This, + IN EFI_GUID *AlgId, + IN CRYPT_HANDLE *Key + ) +{ + EFI_STATUS Status; + CRYPT_HANDLE PubKeyHndl; + UINT8 Hash[SHA256_DIGEST_SIZE]={0}; + UINT8 *KeyFfs, *KeyCmp; + UINTN KeyLen; + UINT32 Flags=0; + INTN err; + + if(!AlgId || !Key || !Key->Blob) + return EFI_INVALID_PARAMETER; + +// Guid must match one of the valid keys we can use in Sig verification. + if(guidcmp(AlgId, &gPRKeyGuid)) + return EFI_UNSUPPORTED; + +// Get PRKey + PubKeyHndl.Blob = NULL; + PubKeyHndl.BlobSize = 0; + Status = GetKey(NULL, &PubKeyHndl, AlgId, 0, Flags); + if(!EFI_ERROR(Status)) + { + KeyFfs = PubKeyHndl.Blob; + KeyLen = PubKeyHndl.BlobSize; + KeyCmp = Key->Blob; + + // If FwKey is Hash of Rsa2048 Key and Key->Algo is Rsa2048 - + // prepare Key for SHA256 Hash compare + if(!guidcmp(&Key->AlgGuid, &gEfiCertRsa2048Guid)) + { + if(!guidcmp(&PubKeyHndl.AlgGuid, &gEfiCertSha256Guid)) + { + KeyCmp = Hash; + KeyLen = SHA256_DIGEST_SIZE; + sha256_vector(1, (const UINT8**)&Key->Blob, (const UINTN*)&Key->BlobSize, Hash); + } else + // if FwKey is x509 and Key->Algo - gEfiCertRsa2048Guid: + // derive nModulus from x509 Key Cert for comparison + if(!guidcmp(&PubKeyHndl.AlgGuid, &gEfiCertX509Guid)) + { + KeyFfs = &Rsa2048Sig[0]; + KeyLen = DEFAULT_RSA_KEY_MODULUS_LEN; + ResetCRmm(); + err = Pkcs7_x509_return_Cert_pubKey((UINT8*)PubKeyHndl.Blob, (UINTN)PubKeyHndl.BlobSize, &KeyFfs,&KeyLen); + ResetCRmm(); + if(err) return EFI_SECURITY_VIOLATION; + } + } + err = MemCmp(KeyFfs, KeyCmp, KeyLen); + + Status = !err ? EFI_SUCCESS:EFI_SECURITY_VIOLATION; + } + return Status; +} +//---------------------------------------------------------------------------- +// END of Crypto DXE Function definitions +//---------------------------------------------------------------------------- + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: InSmmFunction +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InSmmFunction(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + EFI_HANDLE DummyHandle = NULL; + UINT8 *pKey; + + TRACE(((UINTN) -1,"Init Crypto API in SMM\n")); + // + // Init Crypto lib internal state + // + RuntimeCryptLibConstructorInSmm(ImageHandle, SystemTable); + // + // Update Crypto debug traces level + // +#ifdef EFI_DEBUG +// wpa_set_trace_level(CRYPTO_trace_level); +#endif + // + // Get location of PRKey from .ffs + // ReadFfs/FindHob are preboot services whereas Key needs to be available during EFI runtime + // + gKey.Blob = NULL; + Status = CryptoGetFwKey(SystemTable, &gKey); + if(!EFI_ERROR(Status) && gKey.Blob) { + // re-allocate buffer in runtime mem + pKey = gKey.Blob; // preserve the pointer + Status = pSmmBase->SmmAllocatePool(pSmmBase, EfiRuntimeServicesData, gKey.BlobSize, (void**)&pKey); + ASSERT_EFI_ERROR (Status); + if(!EFI_ERROR(Status)) { + MemCpy(pKey, gKey.Blob, gKey.BlobSize); + gKey.Blob = pKey; + } + } + if(EFI_ERROR(Status)) + gKey.Blob = NULL; + + TRACE((TRACE_ALWAYS,"Init: GetKey %r (addr %x(%X, %X), %d bytes)\n", Status, gKey.Blob, gKey.Blob[0], gKey.Blob[1], gKey.BlobSize)); + +/////////////////////////////////////////////////////////////////////////////////// +// Install the SMM clone of Crypto protocols +/////////////////////////////////////////////////////////////////////////////////// + return pBS->InstallMultipleProtocolInterfaces ( + &DummyHandle, + &gAmiSmmDigitalSignatureProtocolGuid, &mAmiSig, + NULL + ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: NotInSmmFunction +// +// Description: This function is called from outside of SMM during SMM registration. +// +// Input: +// IN EFI_HANDLE ImageHandle +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS NotInSmmFunction(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + UINT8 *pKey; + + TRACE(((UINTN) -1,"Init Crypto API NOT in SMM\n")); + // + // Init Crypto lib internal state + // + RuntimeCryptLibConstructor(ImageHandle, SystemTable); + // + // Update Crypto debug traces level + // +#ifdef EFI_DEBUG + wpa_set_trace_level(CRYPTO_trace_level); +#else + wpa_set_trace_level(0); +#endif + // + // Get location of PRKey from .ffs + // ReadFfs/FindHob are preboot services whereas Key needs to be available during EFI runtime + // + gKey.Blob = NULL; + Status = CryptoGetFwKey(SystemTable, &gKey); + if(!EFI_ERROR(Status) && gKey.Blob) { + // re-allocate buffer in runtime mem + pKey = gKey.Blob; // preserve the pointer + Status = pBS->AllocatePool(EfiRuntimeServicesData, gKey.BlobSize, (void**)&pKey); + ASSERT_EFI_ERROR (Status); + if(!EFI_ERROR(Status)) { + MemCpy(pKey, gKey.Blob, gKey.BlobSize); + gKey.Blob = pKey; + } + } + if(EFI_ERROR(Status)) + gKey.Blob = NULL; + + TRACE((TRACE_ALWAYS,"Init: GetKey %r (addr %x(%X, %X), %d bytes)\n", Status, gKey.Blob, gKey.Blob[0], gKey.Blob[1], gKey.BlobSize)); + + +/////////////////////////////////////////////////////////////////////////////// +// +// Install the DXE Crypto protocols +// +/////////////////////////////////////////////////////////////////////////////// + return pBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gAmiDigitalSignatureProtocolGuid, &mAmiSig, + NULL + ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CryptoDxe_Init +// +// Description: Entry point of Crypto DXE driver +// +// Input: EFI_HANDLE ImageHandle, +// EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +CryptoDxe_Init ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + InitAmiLib(ImageHandle, SystemTable); + // + // Install DXE & SMM Crypto Services + // + + return InitSmmHandler(ImageHandle, SystemTable, InSmmFunction, NotInSmmFunction); +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |