diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk')
23 files changed, 5862 insertions, 0 deletions
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c new file mode 100644 index 000000000..2772b1e2b --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c @@ -0,0 +1,192 @@ +/** @file
+ Authenticode Portable Executable Signature Verification over OpenSSL.
+
+ Caution: This module requires additional review when modified.
+ This library will have external input - signature (e.g. PE/COFF Authenticode).
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ AuthenticodeVerify() will get PE/COFF Authenticode and will do basic check for
+ data structure.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+
+//
+// OID ASN.1 Value for SPC_INDIRECT_DATA_OBJID
+//
+UINT8 mSpcIndirectOidValue[] = {
+ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04
+ };
+
+/**
+ Verifies the validity of a PE/COFF Authenticode Signature as described in "Windows
+ Authenticode Portable Executable Signature Format".
+
+ If AuthData is NULL, then return FALSE.
+ If ImageHash is NULL, then return FALSE.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF Authenticode is external input, so this function will do basic check for
+ Authenticode data structure.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed
+ PE/COFF image to be verified.
+ @param[in] DataSize Size of the Authenticode Signature in bytes.
+ @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
+ is used for certificate chain verification.
+ @param[in] CertSize Size of the trusted certificate in bytes.
+ @param[in] ImageHash Pointer to the original image file hash value. The procedure
+ for calculating the image hash value is described in Authenticode
+ specification.
+ @param[in] HashSize Size of Image hash value in bytes.
+
+ @retval TRUE The specified Authenticode Signature is valid.
+ @retval FALSE Invalid Authenticode Signature.
+
+**/
+BOOLEAN
+EFIAPI
+AuthenticodeVerify (
+ IN CONST UINT8 *AuthData,
+ IN UINTN DataSize,
+ IN CONST UINT8 *TrustedCert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *ImageHash,
+ IN UINTN HashSize
+ )
+{
+ BOOLEAN Status;
+ PKCS7 *Pkcs7;
+ CONST UINT8 *Temp;
+ CONST UINT8 *OrigAuthData;
+ UINT8 *SpcIndirectDataContent;
+ UINT8 Asn1Byte;
+ UINTN ContentSize;
+ CONST UINT8 *SpcIndirectDataOid;
+
+ //
+ // Check input parameters.
+ //
+ if ((AuthData == NULL) || (TrustedCert == NULL) || (ImageHash == NULL)) {
+ return FALSE;
+ }
+
+ if ((DataSize > INT_MAX) || (CertSize > INT_MAX) || (HashSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ Pkcs7 = NULL;
+ OrigAuthData = AuthData;
+
+ //
+ // Retrieve & Parse PKCS#7 Data (DER encoding) from Authenticode Signature
+ //
+ Temp = AuthData;
+ Pkcs7 = d2i_PKCS7 (NULL, &Temp, (int)DataSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
+ //
+ if (!PKCS7_type_is_signed (Pkcs7)) {
+ goto _Exit;
+ }
+
+ //
+ // NOTE: OpenSSL PKCS7 Decoder didn't work for Authenticode-format signed data due to
+ // some authenticode-specific structure. Use opaque ASN.1 string to retrieve
+ // PKCS#7 ContentInfo here.
+ //
+ SpcIndirectDataOid = OBJ_get0_data(Pkcs7->d.sign->contents->type);
+ if (OBJ_length(Pkcs7->d.sign->contents->type) != sizeof(mSpcIndirectOidValue) ||
+ CompareMem (
+ SpcIndirectDataOid,
+ mSpcIndirectOidValue,
+ sizeof (mSpcIndirectOidValue)
+ ) != 0) {
+ //
+ // Un-matched SPC_INDIRECT_DATA_OBJID.
+ //
+ goto _Exit;
+ }
+
+
+ SpcIndirectDataContent = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data);
+
+ //
+ // Retrieve the SEQUENCE data size from ASN.1-encoded SpcIndirectDataContent.
+ //
+ Asn1Byte = *(SpcIndirectDataContent + 1);
+
+ if ((Asn1Byte & 0x80) == 0) {
+ //
+ // Short Form of Length Encoding (Length < 128)
+ //
+ ContentSize = (UINTN) (Asn1Byte & 0x7F);
+ //
+ // Skip the SEQUENCE Tag;
+ //
+ SpcIndirectDataContent += 2;
+
+ } else if ((Asn1Byte & 0x81) == 0x81) {
+ //
+ // Long Form of Length Encoding (128 <= Length < 255, Single Octet)
+ //
+ ContentSize = (UINTN) (*(UINT8 *)(SpcIndirectDataContent + 2));
+ //
+ // Skip the SEQUENCE Tag;
+ //
+ SpcIndirectDataContent += 3;
+
+ } else if ((Asn1Byte & 0x82) == 0x82) {
+ //
+ // Long Form of Length Encoding (Length > 255, Two Octet)
+ //
+ ContentSize = (UINTN) (*(UINT8 *)(SpcIndirectDataContent + 2));
+ ContentSize = (ContentSize << 8) + (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 3));
+ //
+ // Skip the SEQUENCE Tag;
+ //
+ SpcIndirectDataContent += 4;
+
+ } else {
+ goto _Exit;
+ }
+
+ //
+ // Compare the original file hash value to the digest retrieve from SpcIndirectDataContent
+ // defined in Authenticode
+ // NOTE: Need to double-check HashLength here!
+ //
+ if (CompareMem (SpcIndirectDataContent + ContentSize - HashSize, ImageHash, HashSize) != 0) {
+ //
+ // Un-matched PE/COFF Hash Value
+ //
+ goto _Exit;
+ }
+
+ //
+ // Verifies the PKCS#7 Signed Data in PE/COFF Authenticode Signature
+ //
+ Status = (BOOLEAN) Pkcs7Verify (OrigAuthData, DataSize, TrustedCert, CertSize, SpcIndirectDataContent, ContentSize);
+
+_Exit:
+ //
+ // Release Resources
+ //
+ PKCS7_free (Pkcs7);
+
+ return Status;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c new file mode 100644 index 000000000..62e8400c4 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c @@ -0,0 +1,45 @@ +/** @file
+ Authenticode Portable Executable Signature Verification which does not provide
+ real capabilities.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Verifies the validity of a PE/COFF Authenticode Signature as described in "Windows
+ Authenticode Portable Executable Signature Format".
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed
+ PE/COFF image to be verified.
+ @param[in] DataSize Size of the Authenticode Signature in bytes.
+ @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
+ is used for certificate chain verification.
+ @param[in] CertSize Size of the trusted certificate in bytes.
+ @param[in] ImageHash Pointer to the original image file hash value. The procedure
+ for calculating the image hash value is described in Authenticode
+ specification.
+ @param[in] HashSize Size of Image hash value in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+AuthenticodeVerify (
+ IN CONST UINT8 *AuthData,
+ IN UINTN DataSize,
+ IN CONST UINT8 *TrustedCert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *ImageHash,
+ IN UINTN HashSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c new file mode 100644 index 000000000..abe4601d1 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c @@ -0,0 +1,306 @@ +/** @file
+ Diffie-Hellman Wrapper Implementation over OpenSSL.
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+/**
+ Allocates and Initializes one Diffie-Hellman Context for subsequent use.
+
+ @return Pointer to the Diffie-Hellman Context that has been initialized.
+ If the allocations fails, DhNew() returns NULL.
+
+**/
+VOID *
+EFIAPI
+DhNew (
+ VOID
+ )
+{
+ //
+ // Allocates & Initializes DH Context by OpenSSL DH_new()
+ //
+ return (VOID *) DH_new ();
+}
+
+/**
+ Release the specified DH context.
+
+ If DhContext is NULL, then return FALSE.
+
+ @param[in] DhContext Pointer to the DH context to be released.
+
+**/
+VOID
+EFIAPI
+DhFree (
+ IN VOID *DhContext
+ )
+{
+ //
+ // Free OpenSSL DH Context
+ //
+ DH_free ((DH *) DhContext);
+}
+
+/**
+ Generates DH parameter.
+
+ Given generator g, and length of prime number p in bits, this function generates p,
+ and sets DH context according to value of g and p.
+
+ Before this function can be invoked, pseudorandom number generator must be correctly
+ initialized by RandomSeed().
+
+ If DhContext is NULL, then return FALSE.
+ If Prime is NULL, then return FALSE.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Value of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[out] Prime Pointer to the buffer to receive the generated prime number.
+
+ @retval TRUE DH parameter generation succeeded.
+ @retval FALSE Value of Generator is not supported.
+ @retval FALSE PRNG fails to generate random prime number with PrimeLength.
+
+**/
+BOOLEAN
+EFIAPI
+DhGenerateParameter (
+ IN OUT VOID *DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ OUT UINT8 *Prime
+ )
+{
+ BOOLEAN RetVal;
+ BIGNUM *BnP;
+
+ //
+ // Check input parameters.
+ //
+ if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
+ return FALSE;
+ }
+
+ if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) {
+ return FALSE;
+ }
+
+ RetVal = (BOOLEAN) DH_generate_parameters_ex (DhContext, (UINT32) PrimeLength, (UINT32) Generator, NULL);
+ if (!RetVal) {
+ return FALSE;
+ }
+
+ DH_get0_pqg (DhContext, (const BIGNUM **)&BnP, NULL, NULL);
+ BN_bn2bin (BnP, Prime);
+
+ return TRUE;
+}
+
+/**
+ Sets generator and prime parameters for DH.
+
+ Given generator g, and prime number p, this function and sets DH
+ context accordingly.
+
+ If DhContext is NULL, then return FALSE.
+ If Prime is NULL, then return FALSE.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Value of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[in] Prime Pointer to the prime number.
+
+ @retval TRUE DH parameter setting succeeded.
+ @retval FALSE Value of Generator is not supported.
+ @retval FALSE Value of Generator is not suitable for the Prime.
+ @retval FALSE Value of Prime is not a prime number.
+ @retval FALSE Value of Prime is not a safe prime number.
+
+**/
+BOOLEAN
+EFIAPI
+DhSetParameter (
+ IN OUT VOID *DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ IN CONST UINT8 *Prime
+ )
+{
+ DH *Dh;
+ BIGNUM *BnP;
+ BIGNUM *BnG;
+
+ //
+ // Check input parameters.
+ //
+ if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
+ return FALSE;
+ }
+
+ if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) {
+ return FALSE;
+ }
+
+ //
+ // Set the generator and prime parameters for DH object.
+ //
+ Dh = (DH *)DhContext;
+ BnP = BN_bin2bn ((const unsigned char *)Prime, (int)(PrimeLength / 8), NULL);
+ BnG = BN_bin2bn ((const unsigned char *)&Generator, 1, NULL);
+ if ((BnP == NULL) || (BnG == NULL) || !DH_set0_pqg (Dh, BnP, NULL, BnG)) {
+ goto Error;
+ }
+
+ return TRUE;
+
+Error:
+ BN_free (BnP);
+ BN_free (BnG);
+
+ return FALSE;
+}
+
+/**
+ Generates DH public key.
+
+ This function generates random secret exponent, and computes the public key, which is
+ returned via parameter PublicKey and PublicKeySize. DH context is updated accordingly.
+ If the PublicKey buffer is too small to hold the public key, FALSE is returned and
+ PublicKeySize is set to the required buffer size to obtain the public key.
+
+ If DhContext is NULL, then return FALSE.
+ If PublicKeySize is NULL, then return FALSE.
+ If PublicKeySize is large enough but PublicKey is NULL, then return FALSE.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[out] PublicKey Pointer to the buffer to receive generated public key.
+ @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes.
+ On output, the size of data returned in PublicKey buffer in bytes.
+
+ @retval TRUE DH public key generation succeeded.
+ @retval FALSE DH public key generation failed.
+ @retval FALSE PublicKeySize is not large enough.
+
+**/
+BOOLEAN
+EFIAPI
+DhGenerateKey (
+ IN OUT VOID *DhContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ BOOLEAN RetVal;
+ DH *Dh;
+ BIGNUM *DhPubKey;
+ INTN Size;
+
+ //
+ // Check input parameters.
+ //
+ if (DhContext == NULL || PublicKeySize == NULL) {
+ return FALSE;
+ }
+
+ if (PublicKey == NULL && *PublicKeySize != 0) {
+ return FALSE;
+ }
+
+ Dh = (DH *) DhContext;
+
+ RetVal = (BOOLEAN) DH_generate_key (DhContext);
+ if (RetVal) {
+ DH_get0_key (Dh, (const BIGNUM **)&DhPubKey, NULL);
+ Size = BN_num_bytes (DhPubKey);
+ if ((Size > 0) && (*PublicKeySize < (UINTN) Size)) {
+ *PublicKeySize = Size;
+ return FALSE;
+ }
+
+ if (PublicKey != NULL) {
+ BN_bn2bin (DhPubKey, PublicKey);
+ }
+ *PublicKeySize = Size;
+ }
+
+ return RetVal;
+}
+
+/**
+ Computes exchanged common key.
+
+ Given peer's public key, this function computes the exchanged common key, based on its own
+ context including value of prime modulus and random secret exponent.
+
+ If DhContext is NULL, then return FALSE.
+ If PeerPublicKey is NULL, then return FALSE.
+ If KeySize is NULL, then return FALSE.
+ If Key is NULL, then return FALSE.
+ If KeySize is not large enough, then return FALSE.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] PeerPublicKey Pointer to the peer's public key.
+ @param[in] PeerPublicKeySize Size of peer's public key in bytes.
+ @param[out] Key Pointer to the buffer to receive generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in bytes.
+ On output, the size of data returned in Key buffer in bytes.
+
+ @retval TRUE DH exchanged key generation succeeded.
+ @retval FALSE DH exchanged key generation failed.
+ @retval FALSE KeySize is not large enough.
+
+**/
+BOOLEAN
+EFIAPI
+DhComputeKey (
+ IN OUT VOID *DhContext,
+ IN CONST UINT8 *PeerPublicKey,
+ IN UINTN PeerPublicKeySize,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ BIGNUM *Bn;
+ INTN Size;
+
+ //
+ // Check input parameters.
+ //
+ if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL || Key == NULL) {
+ return FALSE;
+ }
+
+ if (PeerPublicKeySize > INT_MAX) {
+ return FALSE;
+ }
+
+ Bn = BN_bin2bn (PeerPublicKey, (UINT32) PeerPublicKeySize, NULL);
+ if (Bn == NULL) {
+ return FALSE;
+ }
+
+ Size = DH_compute_key (Key, Bn, DhContext);
+ if (Size < 0) {
+ BN_free (Bn);
+ return FALSE;
+ }
+
+ if (*KeySize < (UINTN) Size) {
+ *KeySize = Size;
+ BN_free (Bn);
+ return FALSE;
+ }
+
+ *KeySize = Size;
+ BN_free (Bn);
+ return TRUE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c new file mode 100644 index 000000000..898708412 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c @@ -0,0 +1,150 @@ +/** @file
+ Diffie-Hellman Wrapper Implementation which does not provide
+ real capabilities.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Allocates and Initializes one Diffie-Hellman Context for subsequent use.
+
+ @return Pointer to the Diffie-Hellman Context that has been initialized.
+ If the interface is not supported, DhNew() returns NULL.
+
+**/
+VOID *
+EFIAPI
+DhNew (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Release the specified DH context.
+
+ If the interface is not supported, then ASSERT().
+
+ @param[in] DhContext Pointer to the DH context to be released.
+
+**/
+VOID
+EFIAPI
+DhFree (
+ IN VOID *DhContext
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Generates DH parameter.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Value of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[out] Prime Pointer to the buffer to receive the generated prime number.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DhGenerateParameter (
+ IN OUT VOID *DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ OUT UINT8 *Prime
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Sets generator and prime parameters for DH.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Value of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[in] Prime Pointer to the prime number.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DhSetParameter (
+ IN OUT VOID *DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ IN CONST UINT8 *Prime
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Generates DH public key.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[out] PublicKey Pointer to the buffer to receive generated public key.
+ @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes.
+ On output, the size of data returned in PublicKey buffer in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DhGenerateKey (
+ IN OUT VOID *DhContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Computes exchanged common key.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] PeerPublicKey Pointer to the peer's public key.
+ @param[in] PeerPublicKeySize Size of peer's public key in bytes.
+ @param[out] Key Pointer to the buffer to receive generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in bytes.
+ On output, the size of data returned in Key buffer in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DhComputeKey (
+ IN OUT VOID *DhContext,
+ IN CONST UINT8 *PeerPublicKey,
+ IN UINTN PeerPublicKeySize,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c new file mode 100644 index 000000000..75225e18e --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c @@ -0,0 +1,208 @@ +/** @file
+ This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Copyright (C) 2016 Microsoft Corporation. All Rights Reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <Library/MemoryAllocationLib.h>
+
+/**
+ Encrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the
+ encrypted message in a newly allocated buffer.
+
+ Things that can cause a failure include:
+ - X509 key size does not match any known key size.
+ - Fail to parse X509 certificate.
+ - Fail to allocate an intermediate buffer.
+ - Null pointer provided for a non-optional parameter.
+ - Data size is too large for the provided key size (max size is a function of key size
+ and hash digest size).
+
+ @param[in] PublicKey A pointer to the DER-encoded X509 certificate that
+ will be used to encrypt the data.
+ @param[in] PublicKeySize Size of the X509 cert buffer.
+ @param[in] InData Data to be encrypted.
+ @param[in] InDataSize Size of the data buffer.
+ @param[in] PrngSeed [Optional] If provided, a pointer to a random seed buffer
+ to be used when initializing the PRNG. NULL otherwise.
+ @param[in] PrngSeedSize [Optional] If provided, size of the random seed buffer.
+ 0 otherwise.
+ @param[out] EncryptedData Pointer to an allocated buffer containing the encrypted
+ message.
+ @param[out] EncryptedDataSize Size of the encrypted message buffer.
+
+ @retval TRUE Encryption was successful.
+ @retval FALSE Encryption failed.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs1v2Encrypt (
+ IN CONST UINT8 *PublicKey,
+ IN UINTN PublicKeySize,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN CONST UINT8 *PrngSeed, OPTIONAL
+ IN UINTN PrngSeedSize, OPTIONAL
+ OUT UINT8 **EncryptedData,
+ OUT UINTN *EncryptedDataSize
+ )
+{
+ BOOLEAN Result;
+ CONST UINT8 *TempPointer;
+ X509 *CertData;
+ EVP_PKEY *InternalPublicKey;
+ EVP_PKEY_CTX *PkeyCtx;
+ UINT8 *OutData;
+ UINTN OutDataSize;
+
+ //
+ // Check input parameters.
+ //
+ if (PublicKey == NULL || InData == NULL ||
+ EncryptedData == NULL || EncryptedDataSize == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Check public key size.
+ //
+ if (PublicKeySize > 0xFFFFFFFF) {
+ //
+ // Public key size is too large for implementation.
+ //
+ return FALSE;
+ }
+
+ *EncryptedData = NULL;
+ *EncryptedDataSize = 0;
+ Result = FALSE;
+ TempPointer = NULL;
+ CertData = NULL;
+ InternalPublicKey = NULL;
+ PkeyCtx = NULL;
+ OutData = NULL;
+ OutDataSize = 0;
+
+ //
+ // If it provides a seed then use it.
+ // Ohterwise, we'll seed with fixed values and hope that the PRNG has already been
+ // used enough to generate sufficient entropy.
+ //
+ if (PrngSeed != NULL) {
+ RandomSeed (PrngSeed, PrngSeedSize);
+ } else {
+ RandomSeed (NULL, 0);
+ }
+
+ //
+ // Parse the X509 cert and extract the public key.
+ //
+ TempPointer = PublicKey;
+ CertData = d2i_X509 (&CertData, &TempPointer, (UINT32)PublicKeySize);
+ if (CertData == NULL) {
+ //
+ // Fail to parse X509 cert.
+ //
+ goto _Exit;
+ }
+
+ //
+ // Extract the public key from the x509 cert in a format that
+ // OpenSSL can use.
+ //
+ InternalPublicKey = X509_get_pubkey (CertData);
+ if (InternalPublicKey == NULL) {
+ //
+ // Fail to extract public key.
+ //
+ goto _Exit;
+ }
+
+ //
+ // Create a context for the public key operation.
+ //
+ PkeyCtx = EVP_PKEY_CTX_new (InternalPublicKey, NULL);
+ if (PkeyCtx == NULL) {
+ //
+ // Fail to create contex.
+ //
+ goto _Exit;
+ }
+ //
+ // Initialize the context and set the desired padding.
+ //
+ if (EVP_PKEY_encrypt_init (PkeyCtx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding (PkeyCtx, RSA_PKCS1_OAEP_PADDING) <= 0) {
+ //
+ // Fail to initialize the context.
+ //
+ goto _Exit;
+ }
+
+ //
+ // Determine the required buffer length for malloc'ing.
+ //
+ if (EVP_PKEY_encrypt (PkeyCtx, NULL, &OutDataSize, InData, InDataSize) <= 0) {
+ //
+ // Fail to determine output buffer size.
+ //
+ goto _Exit;
+ }
+
+ //
+ // Allocate a buffer for the output data.
+ //
+ OutData = AllocatePool (OutDataSize);
+ if (OutData == NULL) {
+ //
+ // Fail to allocate the output buffer.
+ //
+ goto _Exit;
+ }
+
+ //
+ // Encrypt Data.
+ //
+ if (EVP_PKEY_encrypt (PkeyCtx, OutData, &OutDataSize, InData, InDataSize) <= 0) {
+ //
+ // Fail to encrypt data, need to free the output buffer.
+ //
+ FreePool (OutData);
+ OutData = NULL;
+ OutDataSize = 0;
+ goto _Exit;
+ }
+
+ //
+ // Encrypt done.
+ //
+ *EncryptedData = OutData;
+ *EncryptedDataSize = OutDataSize;
+ Result = TRUE;
+
+_Exit:
+ //
+ // Release Resources
+ //
+ if (CertData != NULL) {
+ X509_free (CertData );
+ }
+ if (InternalPublicKey != NULL) {
+ EVP_PKEY_free (InternalPublicKey);
+ }
+ if (PkeyCtx != NULL) {
+ EVP_PKEY_CTX_free (PkeyCtx);
+ }
+
+ return Result;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c new file mode 100644 index 000000000..6571fc4a2 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c @@ -0,0 +1,51 @@ +/** @file
+ This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Copyright (C) 2016 Microsoft Corporation. All Rights Reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Encrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the
+ encrypted message in a newly allocated buffer.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] PublicKey A pointer to the DER-encoded X509 certificate that
+ will be used to encrypt the data.
+ @param[in] PublicKeySize Size of the X509 cert buffer.
+ @param[in] InData Data to be encrypted.
+ @param[in] InDataSize Size of the data buffer.
+ @param[in] PrngSeed [Optional] If provided, a pointer to a random seed buffer
+ to be used when initializing the PRNG. NULL otherwise.
+ @param[in] PrngSeedSize [Optional] If provided, size of the random seed buffer.
+ 0 otherwise.
+ @param[out] EncryptedData Pointer to an allocated buffer containing the encrypted
+ message.
+ @param[out] EncryptedDataSize Size of the encrypted message buffer.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs1v2Encrypt (
+ IN CONST UINT8 *PublicKey,
+ IN UINTN PublicKeySize,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN CONST UINT8 *PrngSeed, OPTIONAL
+ IN UINTN PrngSeedSize, OPTIONAL
+ OUT UINT8 **EncryptedData,
+ OUT UINTN *EncryptedDataSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c new file mode 100644 index 000000000..a89c1525c --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c @@ -0,0 +1,95 @@ +/** @file
+ PBKDF2 Key Derivation Function Wrapper Implementation over OpenSSL.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+/**
+ Derives a key from a password using a salt and iteration count, based on PKCS#5 v2.0
+ password based encryption key derivation function PBKDF2, as specified in RFC 2898.
+
+ If Password or Salt or OutKey is NULL, then return FALSE.
+ If the hash algorithm could not be determined, then return FALSE.
+
+ @param[in] PasswordLength Length of input password in bytes.
+ @param[in] Password Pointer to the array for the password.
+ @param[in] SaltLength Size of the Salt in bytes.
+ @param[in] Salt Pointer to the Salt.
+ @param[in] IterationCount Number of iterations to perform. Its value should be
+ greater than or equal to 1.
+ @param[in] DigestSize Size of the message digest to be used (eg. SHA256_DIGEST_SIZE).
+ NOTE: DigestSize will be used to determine the hash algorithm.
+ Only SHA1_DIGEST_SIZE or SHA256_DIGEST_SIZE is supported.
+ @param[in] KeyLength Size of the derived key buffer in bytes.
+ @param[out] OutKey Pointer to the output derived key buffer.
+
+ @retval TRUE A key was derived successfully.
+ @retval FALSE One of the pointers was NULL or one of the sizes was too large.
+ @retval FALSE The hash algorithm could not be determined from the digest size.
+ @retval FALSE The key derivation operation failed.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs5HashPassword (
+ IN UINTN PasswordLength,
+ IN CONST CHAR8 *Password,
+ IN UINTN SaltLength,
+ IN CONST UINT8 *Salt,
+ IN UINTN IterationCount,
+ IN UINTN DigestSize,
+ IN UINTN KeyLength,
+ OUT UINT8 *OutKey
+ )
+{
+ CONST EVP_MD *HashAlg;
+
+ HashAlg = NULL;
+
+ //
+ // Parameter Checking.
+ //
+ if ((Password == NULL) || (Salt == NULL) || (OutKey == NULL)) {
+ return FALSE;
+ }
+ if ((PasswordLength == 0) || (PasswordLength > INT_MAX) ||
+ (SaltLength == 0) || (SaltLength > INT_MAX) ||
+ (KeyLength == 0) || (KeyLength > INT_MAX) ||
+ (IterationCount < 1) || (IterationCount > INT_MAX)) {
+ return FALSE;
+ }
+ //
+ // Make sure the digest algorithm is supported.
+ //
+ switch (DigestSize) {
+ case SHA1_DIGEST_SIZE:
+ HashAlg = EVP_sha1();
+ break;
+ case SHA256_DIGEST_SIZE:
+ HashAlg = EVP_sha256();
+ break;
+ default:
+ return FALSE;
+ break;
+ }
+
+ //
+ // Perform password-based key derivation routines.
+ //
+ return (BOOLEAN)PKCS5_PBKDF2_HMAC (
+ (const char *)Password,
+ (int)PasswordLength,
+ (const unsigned char *)Salt,
+ (int)SaltLength,
+ (int)IterationCount,
+ HashAlg,
+ (int)KeyLength,
+ (unsigned char *)OutKey
+ );
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c new file mode 100644 index 000000000..b8a41fbb2 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c @@ -0,0 +1,50 @@ +/** @file
+ PBKDF2 Key Derivation Function Wrapper Implementation which does not provide real
+ capabilities.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+/**
+ Derives a key from a password using a salt and iteration count, based on PKCS#5 v2.0
+ password based encryption key derivation function PBKDF2, as specified in RFC 2898.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] PasswordLength Length of input password in bytes.
+ @param[in] Password Pointer to the array for the password.
+ @param[in] SaltLength Size of the Salt in bytes.
+ @param[in] Salt Pointer to the Salt.
+ @param[in] IterationCount Number of iterations to perform. Its value should be
+ greater than or equal to 1.
+ @param[in] DigestSize Size of the message digest to be used (eg. SHA256_DIGEST_SIZE).
+ NOTE: DigestSize will be used to determine the hash algorithm.
+ Only SHA1_DIGEST_SIZE or SHA256_DIGEST_SIZE is supported.
+ @param[in] KeyLength Size of the derived key buffer in bytes.
+ @param[out] OutKey Pointer to the output derived key buffer.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs5HashPassword (
+ IN UINTN PasswordLength,
+ IN CONST CHAR8 *Password,
+ IN UINTN SaltLength,
+ IN CONST UINT8 *Salt,
+ IN UINTN IterationCount,
+ IN UINTN DigestSize,
+ IN UINTN KeyLength,
+ OUT UINT8 *OutKey
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c new file mode 100644 index 000000000..442f573f8 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c @@ -0,0 +1,194 @@ +/** @file
+ PKCS#7 SignedData Sign Wrapper Implementation over OpenSSL.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+
+/**
+ Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
+ Syntax Standard, version 1.5". This interface is only intended to be used for
+ application to perform PKCS#7 functionality validation.
+
+ @param[in] PrivateKey Pointer to the PEM-formatted private key data for
+ data signing.
+ @param[in] PrivateKeySize Size of the PEM private key data in bytes.
+ @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM
+ key data.
+ @param[in] InData Pointer to the content to be signed.
+ @param[in] InDataSize Size of InData in bytes.
+ @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.
+ @param[in] OtherCerts Pointer to an optional additional set of certificates to
+ include in the PKCS#7 signedData (e.g. any intermediate
+ CAs in the chain).
+ @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's
+ responsibility to free the buffer with FreePool().
+ @param[out] SignedDataSize Size of SignedData in bytes.
+
+ @retval TRUE PKCS#7 data signing succeeded.
+ @retval FALSE PKCS#7 data signing failed.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7Sign (
+ IN CONST UINT8 *PrivateKey,
+ IN UINTN PrivateKeySize,
+ IN CONST UINT8 *KeyPassword,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *SignCert,
+ IN UINT8 *OtherCerts OPTIONAL,
+ OUT UINT8 **SignedData,
+ OUT UINTN *SignedDataSize
+ )
+{
+ BOOLEAN Status;
+ EVP_PKEY *Key;
+ BIO *DataBio;
+ PKCS7 *Pkcs7;
+ UINT8 *RsaContext;
+ UINT8 *P7Data;
+ UINTN P7DataSize;
+ UINT8 *Tmp;
+
+ //
+ // Check input parameters.
+ //
+ if (PrivateKey == NULL || KeyPassword == NULL || InData == NULL ||
+ SignCert == NULL || SignedData == NULL || SignedDataSize == NULL || InDataSize > INT_MAX) {
+ return FALSE;
+ }
+
+ RsaContext = NULL;
+ Key = NULL;
+ Pkcs7 = NULL;
+ DataBio = NULL;
+ Status = FALSE;
+
+ //
+ // Retrieve RSA private key from PEM data.
+ //
+ Status = RsaGetPrivateKeyFromPem (
+ PrivateKey,
+ PrivateKeySize,
+ (CONST CHAR8 *) KeyPassword,
+ (VOID **) &RsaContext
+ );
+ if (!Status) {
+ return Status;
+ }
+
+ Status = FALSE;
+
+ //
+ // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling
+ //
+ if (EVP_add_digest (EVP_md5 ()) == 0) {
+ goto _Exit;
+ }
+ if (EVP_add_digest (EVP_sha1 ()) == 0) {
+ goto _Exit;
+ }
+ if (EVP_add_digest (EVP_sha256 ()) == 0) {
+ goto _Exit;
+ }
+
+ RandomSeed (NULL, 0);
+
+ //
+ // Construct OpenSSL EVP_PKEY for private key.
+ //
+ Key = EVP_PKEY_new ();
+ if (Key == NULL) {
+ goto _Exit;
+ }
+ if (EVP_PKEY_assign_RSA (Key, (RSA *) RsaContext) == 0) {
+ goto _Exit;
+ }
+
+ //
+ // Convert the data to be signed to BIO format.
+ //
+ DataBio = BIO_new (BIO_s_mem ());
+ if (DataBio == NULL) {
+ goto _Exit;
+ }
+
+ if (BIO_write (DataBio, InData, (int) InDataSize) <= 0) {
+ goto _Exit;
+ }
+
+ //
+ // Create the PKCS#7 signedData structure.
+ //
+ Pkcs7 = PKCS7_sign (
+ (X509 *) SignCert,
+ Key,
+ (STACK_OF(X509) *) OtherCerts,
+ DataBio,
+ PKCS7_BINARY | PKCS7_NOATTR | PKCS7_DETACHED
+ );
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Convert PKCS#7 signedData structure into DER-encoded buffer.
+ //
+ P7DataSize = i2d_PKCS7 (Pkcs7, NULL);
+ if (P7DataSize <= 19) {
+ goto _Exit;
+ }
+
+ P7Data = malloc (P7DataSize);
+ if (P7Data == NULL) {
+ goto _Exit;
+ }
+
+ Tmp = P7Data;
+ P7DataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &Tmp);
+ ASSERT (P7DataSize > 19);
+
+ //
+ // Strip ContentInfo to content only for signeddata. The data be trimmed off
+ // is totally 19 bytes.
+ //
+ *SignedDataSize = P7DataSize - 19;
+ *SignedData = AllocatePool (*SignedDataSize);
+ if (*SignedData == NULL) {
+ OPENSSL_free (P7Data);
+ goto _Exit;
+ }
+
+ CopyMem (*SignedData, P7Data + 19, *SignedDataSize);
+
+ OPENSSL_free (P7Data);
+
+ Status = TRUE;
+
+_Exit:
+ //
+ // Release Resources
+ //
+ if (Key != NULL) {
+ EVP_PKEY_free (Key);
+ }
+
+ if (DataBio != NULL) {
+ BIO_free (DataBio);
+ }
+
+ if (Pkcs7 != NULL) {
+ PKCS7_free (Pkcs7);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c new file mode 100644 index 000000000..d7ff8ba94 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c @@ -0,0 +1,54 @@ +/** @file
+ PKCS#7 SignedData Sign Wrapper Implementation which does not provide real
+ capabilities.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
+ Syntax Standard, version 1.5". This interface is only intended to be used for
+ application to perform PKCS#7 functionality validation.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] PrivateKey Pointer to the PEM-formatted private key data for
+ data signing.
+ @param[in] PrivateKeySize Size of the PEM private key data in bytes.
+ @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM
+ key data.
+ @param[in] InData Pointer to the content to be signed.
+ @param[in] InDataSize Size of InData in bytes.
+ @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.
+ @param[in] OtherCerts Pointer to an optional additional set of certificates to
+ include in the PKCS#7 signedData (e.g. any intermediate
+ CAs in the chain).
+ @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's
+ responsibility to free the buffer with FreePool().
+ @param[out] SignedDataSize Size of SignedData in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7Sign (
+ IN CONST UINT8 *PrivateKey,
+ IN UINTN PrivateKeySize,
+ IN CONST UINT8 *KeyPassword,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *SignCert,
+ IN UINT8 *OtherCerts OPTIONAL,
+ OUT UINT8 **SignedData,
+ OUT UINTN *SignedDataSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c new file mode 100644 index 000000000..112c13c22 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c @@ -0,0 +1,190 @@ +/** @file
+ Non-runtime specific implementation of PKCS#7 SignedData Verification Wrapper.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pkcs7.h>
+
+/**
+ Check the contents of PKCS7 is not data.
+
+ It is copied from PKCS7_type_is_other() in pk7_doit.c.
+
+ @param[in] P7 Pointer to the location at which the PKCS7 is located.
+
+ @retval TRUE If the type is others.
+ @retval FALSE If the type is expected.
+**/
+STATIC
+BOOLEAN
+Pkcs7TypeIsOther (
+ IN PKCS7 *P7
+ )
+{
+ BOOLEAN Others;
+ INTN Nid = OBJ_obj2nid (P7->type);
+
+ switch (Nid) {
+ case NID_pkcs7_data:
+ case NID_pkcs7_signed:
+ case NID_pkcs7_enveloped:
+ case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_encrypted:
+ Others = FALSE;
+ break;
+ default:
+ Others = TRUE;
+ }
+
+ return Others;
+}
+
+/**
+ Get the ASN.1 string for the PKCS7.
+
+ It is copied from PKCS7_get_octet_string() in pk7_doit.c.
+
+ @param[in] P7 Pointer to the location at which the PKCS7 is located.
+
+ @return ASN1_OCTET_STRING ASN.1 string.
+**/
+STATIC
+ASN1_OCTET_STRING*
+Pkcs7GetOctetString (
+ IN PKCS7 *P7
+ )
+{
+ if (PKCS7_type_is_data (P7)) {
+ return P7->d.data;
+ }
+
+ if (Pkcs7TypeIsOther(P7) && (P7->d.other != NULL) &&
+ (P7->d.other->type == V_ASN1_OCTET_STRING)) {
+ return P7->d.other->value.octet_string;
+ }
+
+ return NULL;
+}
+
+/**
+ Extracts the attached content from a PKCS#7 signed data if existed. The input signed
+ data could be wrapped in a ContentInfo structure.
+
+ If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,
+ then return FALSE. If the P7Data is not correctly formatted, then return FALSE.
+
+ Caution: This function may receive untrusted input. So this function will do
+ basic check for PKCS#7 data structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 signed data to process.
+ @param[in] P7Length Length of the PKCS#7 signed data in bytes.
+ @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.
+ It's caller's responsibility to free the buffer with FreePool().
+ @param[out] ContentSize The size of the extracted content in bytes.
+
+ @retval TRUE The P7Data was correctly formatted for processing.
+ @retval FALSE The P7Data was not correctly formatted for processing.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetAttachedContent (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT VOID **Content,
+ OUT UINTN *ContentSize
+ )
+{
+ BOOLEAN Status;
+ PKCS7 *Pkcs7;
+ UINT8 *SignedData;
+ UINTN SignedDataSize;
+ BOOLEAN Wrapped;
+ CONST UINT8 *Temp;
+ ASN1_OCTET_STRING *OctStr;
+
+ //
+ // Check input parameter.
+ //
+ if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {
+ return FALSE;
+ }
+
+ *Content = NULL;
+ Pkcs7 = NULL;
+ SignedData = NULL;
+ OctStr = NULL;
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
+ if (!Status || (SignedDataSize > INT_MAX)) {
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ //
+ // Decoding PKCS#7 SignedData
+ //
+ Temp = SignedData;
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // The type of Pkcs7 must be signedData
+ //
+ if (!PKCS7_type_is_signed (Pkcs7)) {
+ goto _Exit;
+ }
+
+ //
+ // Check for detached or attached content
+ //
+ if (PKCS7_get_detached (Pkcs7)) {
+ //
+ // No Content supplied for PKCS7 detached signedData
+ //
+ *Content = NULL;
+ *ContentSize = 0;
+ } else {
+ //
+ // Retrieve the attached content in PKCS7 signedData
+ //
+ OctStr = Pkcs7GetOctetString (Pkcs7->d.sign->contents);
+ if (OctStr == NULL) {
+ goto _Exit;
+ }
+
+ if ((OctStr->length > 0) && (OctStr->data != NULL)) {
+ *ContentSize = OctStr->length;
+ *Content = AllocatePool (*ContentSize);
+ if (*Content == NULL) {
+ *ContentSize = 0;
+ goto _Exit;
+ }
+ CopyMem (*Content, OctStr->data, *ContentSize);
+ }
+ }
+ Status = TRUE;
+
+_Exit:
+ //
+ // Release Resources
+ //
+ PKCS7_free (Pkcs7);
+
+ if (!Wrapped) {
+ OPENSSL_free (SignedData);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c new file mode 100644 index 000000000..d99597d18 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c @@ -0,0 +1,910 @@ +/** @file
+ PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.
+
+ Caution: This module requires additional review when modified.
+ This library will have external input - signature (e.g. UEFI Authenticated
+ Variable). It may by input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated
+ Variable and will do basic check for data structure.
+
+Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pkcs7.h>
+
+UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
+
+/**
+ Check input P7Data is a wrapped ContentInfo structure or not. If not construct
+ a new structure to wrap P7Data.
+
+ Caution: This function may receive untrusted input.
+ UEFI Authenticated Variable is external input, so this function will do basic
+ check for PKCS#7 data structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 message to verify.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise
+ return FALSE.
+ @param[out] WrapData If return status of this function is TRUE:
+ 1) when WrapFlag is TRUE, pointer to P7Data.
+ 2) when WrapFlag is FALSE, pointer to a new ContentInfo
+ structure. It's caller's responsibility to free this
+ buffer.
+ @param[out] WrapDataSize Length of ContentInfo structure in bytes.
+
+ @retval TRUE The operation is finished successfully.
+ @retval FALSE The operation is failed due to lack of resources.
+
+**/
+BOOLEAN
+WrapPkcs7Data (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT BOOLEAN *WrapFlag,
+ OUT UINT8 **WrapData,
+ OUT UINTN *WrapDataSize
+ )
+{
+ BOOLEAN Wrapped;
+ UINT8 *SignedData;
+
+ //
+ // Check whether input P7Data is a wrapped ContentInfo structure or not.
+ //
+ Wrapped = FALSE;
+ if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {
+ if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {
+ if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {
+ Wrapped = TRUE;
+ }
+ }
+ }
+
+ if (Wrapped) {
+ *WrapData = (UINT8 *) P7Data;
+ *WrapDataSize = P7Length;
+ } else {
+ //
+ // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.
+ //
+ *WrapDataSize = P7Length + 19;
+ *WrapData = malloc (*WrapDataSize);
+ if (*WrapData == NULL) {
+ *WrapFlag = Wrapped;
+ return FALSE;
+ }
+
+ SignedData = *WrapData;
+
+ //
+ // Part1: 0x30, 0x82.
+ //
+ SignedData[0] = 0x30;
+ SignedData[1] = 0x82;
+
+ //
+ // Part2: Length1 = P7Length + 19 - 4, in big endian.
+ //
+ SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);
+ SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);
+
+ //
+ // Part3: 0x06, 0x09.
+ //
+ SignedData[4] = 0x06;
+ SignedData[5] = 0x09;
+
+ //
+ // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.
+ //
+ CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));
+
+ //
+ // Part5: 0xA0, 0x82.
+ //
+ SignedData[15] = 0xA0;
+ SignedData[16] = 0x82;
+
+ //
+ // Part6: Length2 = P7Length, in big endian.
+ //
+ SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);
+ SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);
+
+ //
+ // Part7: P7Data.
+ //
+ CopyMem (SignedData + 19, P7Data, P7Length);
+ }
+
+ *WrapFlag = Wrapped;
+ return TRUE;
+}
+
+/**
+ Pop single certificate from STACK_OF(X509).
+
+ If X509Stack, Cert, or CertSize is NULL, then return FALSE.
+
+ @param[in] X509Stack Pointer to a X509 stack object.
+ @param[out] Cert Pointer to a X509 certificate.
+ @param[out] CertSize Length of output X509 certificate in bytes.
+
+ @retval TRUE The X509 stack pop succeeded.
+ @retval FALSE The pop operation failed.
+
+**/
+BOOLEAN
+X509PopCertificate (
+ IN VOID *X509Stack,
+ OUT UINT8 **Cert,
+ OUT UINTN *CertSize
+ )
+{
+ BIO *CertBio;
+ X509 *X509Cert;
+ STACK_OF(X509) *CertStack;
+ BOOLEAN Status;
+ INT32 Result;
+ BUF_MEM *Ptr;
+ INT32 Length;
+ VOID *Buffer;
+
+ Status = FALSE;
+
+ if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {
+ return Status;
+ }
+
+ CertStack = (STACK_OF(X509) *) X509Stack;
+
+ X509Cert = sk_X509_pop (CertStack);
+
+ if (X509Cert == NULL) {
+ return Status;
+ }
+
+ Buffer = NULL;
+
+ CertBio = BIO_new (BIO_s_mem ());
+ if (CertBio == NULL) {
+ return Status;
+ }
+
+ Result = i2d_X509_bio (CertBio, X509Cert);
+ if (Result == 0) {
+ goto _Exit;
+ }
+
+ BIO_get_mem_ptr (CertBio, &Ptr);
+ Length = (INT32)(Ptr->length);
+ if (Length <= 0) {
+ goto _Exit;
+ }
+
+ Buffer = malloc (Length);
+ if (Buffer == NULL) {
+ goto _Exit;
+ }
+
+ Result = BIO_read (CertBio, Buffer, Length);
+ if (Result != Length) {
+ goto _Exit;
+ }
+
+ *Cert = Buffer;
+ *CertSize = Length;
+
+ Status = TRUE;
+
+_Exit:
+
+ BIO_free (CertBio);
+
+ if (!Status && (Buffer != NULL)) {
+ free (Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard". The input signed data could be wrapped
+ in a ContentInfo structure.
+
+ If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then
+ return FALSE. If P7Length overflow, then return FALSE.
+
+ Caution: This function may receive untrusted input.
+ UEFI Authenticated Variable is external input, so this function will do basic
+ check for PKCS#7 data structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 message to verify.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.
+ It's caller's responsibility to free the buffer with
+ Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] StackLength Length of signer's certificates in bytes.
+ @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.
+ It's caller's responsibility to free the buffer with
+ Pkcs7FreeSigners().
+ @param[out] CertLength Length of the trusted certificate in bytes.
+
+ @retval TRUE The operation is finished successfully.
+ @retval FALSE Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetSigners (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT UINT8 **CertStack,
+ OUT UINTN *StackLength,
+ OUT UINT8 **TrustedCert,
+ OUT UINTN *CertLength
+ )
+{
+ PKCS7 *Pkcs7;
+ BOOLEAN Status;
+ UINT8 *SignedData;
+ CONST UINT8 *Temp;
+ UINTN SignedDataSize;
+ BOOLEAN Wrapped;
+ STACK_OF(X509) *Stack;
+ UINT8 Index;
+ UINT8 *CertBuf;
+ UINT8 *OldBuf;
+ UINTN BufferSize;
+ UINTN OldSize;
+ UINT8 *SingleCert;
+ UINTN SingleCertSize;
+
+ if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||
+ (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) {
+ return FALSE;
+ }
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
+ if (!Status) {
+ return Status;
+ }
+
+ Status = FALSE;
+ Pkcs7 = NULL;
+ Stack = NULL;
+ CertBuf = NULL;
+ OldBuf = NULL;
+ SingleCert = NULL;
+
+ //
+ // Retrieve PKCS#7 Data (DER encoding)
+ //
+ if (SignedDataSize > INT_MAX) {
+ goto _Exit;
+ }
+
+ Temp = SignedData;
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
+ //
+ if (!PKCS7_type_is_signed (Pkcs7)) {
+ goto _Exit;
+ }
+
+ Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY);
+ if (Stack == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Convert CertStack to buffer in following format:
+ // UINT8 CertNumber;
+ // UINT32 Cert1Length;
+ // UINT8 Cert1[];
+ // UINT32 Cert2Length;
+ // UINT8 Cert2[];
+ // ...
+ // UINT32 CertnLength;
+ // UINT8 Certn[];
+ //
+ BufferSize = sizeof (UINT8);
+ OldSize = BufferSize;
+
+ for (Index = 0; ; Index++) {
+ Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);
+ if (!Status) {
+ break;
+ }
+
+ OldSize = BufferSize;
+ OldBuf = CertBuf;
+ BufferSize = OldSize + SingleCertSize + sizeof (UINT32);
+ CertBuf = malloc (BufferSize);
+
+ if (CertBuf == NULL) {
+ goto _Exit;
+ }
+
+ if (OldBuf != NULL) {
+ CopyMem (CertBuf, OldBuf, OldSize);
+ free (OldBuf);
+ OldBuf = NULL;
+ }
+
+ WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize);
+ CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);
+
+ free (SingleCert);
+ SingleCert = NULL;
+ }
+
+ if (CertBuf != NULL) {
+ //
+ // Update CertNumber.
+ //
+ CertBuf[0] = Index;
+
+ *CertLength = BufferSize - OldSize - sizeof (UINT32);
+ *TrustedCert = malloc (*CertLength);
+ if (*TrustedCert == NULL) {
+ goto _Exit;
+ }
+
+ CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);
+ *CertStack = CertBuf;
+ *StackLength = BufferSize;
+ Status = TRUE;
+ }
+
+_Exit:
+ //
+ // Release Resources
+ //
+ if (!Wrapped) {
+ free (SignedData);
+ }
+
+ if (Pkcs7 != NULL) {
+ PKCS7_free (Pkcs7);
+ }
+
+ if (Stack != NULL) {
+ sk_X509_pop_free(Stack, X509_free);
+ }
+
+ if (SingleCert != NULL) {
+ free (SingleCert);
+ }
+
+ if (!Status && (CertBuf != NULL)) {
+ free (CertBuf);
+ *CertStack = NULL;
+ }
+
+ if (OldBuf != NULL) {
+ free (OldBuf);
+ }
+
+ return Status;
+}
+
+/**
+ Wrap function to use free() to free allocated memory for certificates.
+
+ @param[in] Certs Pointer to the certificates to be freed.
+
+**/
+VOID
+EFIAPI
+Pkcs7FreeSigners (
+ IN UINT8 *Certs
+ )
+{
+ if (Certs == NULL) {
+ return;
+ }
+
+ free (Certs);
+}
+
+/**
+ Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard", and outputs two certificate lists chained and
+ unchained to the signer's certificates.
+ The input signed data could be wrapped in a ContentInfo structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 message.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[out] SignerChainCerts Pointer to the certificates list chained to signer's
+ certificate. It's caller's responsibility to free the buffer
+ with Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] ChainLength Length of the chained certificates list buffer in bytes.
+ @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's
+ responsibility to free the buffer with Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] UnchainLength Length of the unchained certificates list buffer in bytes.
+
+ @retval TRUE The operation is finished successfully.
+ @retval FALSE Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT UINT8 **SignerChainCerts,
+ OUT UINTN *ChainLength,
+ OUT UINT8 **UnchainCerts,
+ OUT UINTN *UnchainLength
+ )
+{
+ BOOLEAN Status;
+ UINT8 *NewP7Data;
+ UINTN NewP7Length;
+ BOOLEAN Wrapped;
+ UINT8 Index;
+ PKCS7 *Pkcs7;
+ X509_STORE_CTX *CertCtx;
+ STACK_OF(X509) *CtxChain;
+ STACK_OF(X509) *CtxUntrusted;
+ X509 *CtxCert;
+ STACK_OF(X509) *Signers;
+ X509 *Signer;
+ X509 *Cert;
+ X509 *Issuer;
+ X509_NAME *IssuerName;
+ UINT8 *CertBuf;
+ UINT8 *OldBuf;
+ UINTN BufferSize;
+ UINTN OldSize;
+ UINT8 *SingleCert;
+ UINTN CertSize;
+
+ //
+ // Initializations
+ //
+ Status = FALSE;
+ NewP7Data = NULL;
+ Pkcs7 = NULL;
+ CertCtx = NULL;
+ CtxChain = NULL;
+ CtxCert = NULL;
+ CtxUntrusted = NULL;
+ Cert = NULL;
+ SingleCert = NULL;
+ CertBuf = NULL;
+ OldBuf = NULL;
+ Signers = NULL;
+
+ ZeroMem (&CertCtx, sizeof (CertCtx));
+
+ //
+ // Parameter Checking
+ //
+ if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||
+ (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) {
+ return Status;
+ }
+
+ *SignerChainCerts = NULL;
+ *ChainLength = 0;
+ *UnchainCerts = NULL;
+ *UnchainLength = 0;
+
+ //
+ // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.
+ //
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);
+ if (!Status || (NewP7Length > INT_MAX)) {
+ goto _Error;
+ }
+
+ //
+ // Decodes PKCS#7 SignedData
+ //
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length);
+ if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {
+ goto _Error;
+ }
+
+ //
+ // Obtains Signer's Certificate from PKCS#7 data
+ // NOTE: Only one signer case will be handled in this function, which means SignerInfos
+ // should include only one signer's certificate.
+ //
+ Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);
+ if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {
+ goto _Error;
+ }
+ Signer = sk_X509_value (Signers, 0);
+
+ CertCtx = X509_STORE_CTX_new ();
+ if (CertCtx == NULL) {
+ goto _Error;
+ }
+ if (!X509_STORE_CTX_init (CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {
+ goto _Error;
+ }
+ //
+ // Initialize Chained & Untrusted stack
+ //
+ CtxChain = X509_STORE_CTX_get0_chain (CertCtx);
+ CtxCert = X509_STORE_CTX_get0_cert (CertCtx);
+ if (CtxChain == NULL) {
+ if (((CtxChain = sk_X509_new_null ()) == NULL) ||
+ (!sk_X509_push (CtxChain, CtxCert))) {
+ goto _Error;
+ }
+ }
+ CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);
+ if (CtxUntrusted != NULL) {
+ (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);
+ }
+
+ //
+ // Build certificates stack chained from Signer's certificate.
+ //
+ Cert = Signer;
+ for (; ;) {
+ //
+ // Self-Issue checking
+ //
+ Issuer = NULL;
+ if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {
+ if (X509_cmp (Issuer, Cert) == 0) {
+ break;
+ }
+ }
+
+ //
+ // Found the issuer of the current certificate
+ //
+ if (CtxUntrusted != NULL) {
+ Issuer = NULL;
+ IssuerName = X509_get_issuer_name (Cert);
+ Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);
+ if (Issuer != NULL) {
+ if (!sk_X509_push (CtxChain, Issuer)) {
+ goto _Error;
+ }
+ (VOID)sk_X509_delete_ptr (CtxUntrusted, Issuer);
+
+ Cert = Issuer;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Converts Chained and Untrusted Certificate to Certificate Buffer in following format:
+ // UINT8 CertNumber;
+ // UINT32 Cert1Length;
+ // UINT8 Cert1[];
+ // UINT32 Cert2Length;
+ // UINT8 Cert2[];
+ // ...
+ // UINT32 CertnLength;
+ // UINT8 Certn[];
+ //
+
+ if (CtxChain != NULL) {
+ BufferSize = sizeof (UINT8);
+ CertBuf = NULL;
+
+ for (Index = 0; ; Index++) {
+ Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize);
+ if (!Status) {
+ break;
+ }
+
+ OldSize = BufferSize;
+ OldBuf = CertBuf;
+ BufferSize = OldSize + CertSize + sizeof (UINT32);
+ CertBuf = malloc (BufferSize);
+
+ if (CertBuf == NULL) {
+ Status = FALSE;
+ goto _Error;
+ }
+ if (OldBuf != NULL) {
+ CopyMem (CertBuf, OldBuf, OldSize);
+ free (OldBuf);
+ OldBuf = NULL;
+ }
+
+ WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
+ CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
+
+ free (SingleCert);
+ SingleCert = NULL;
+ }
+
+ if (CertBuf != NULL) {
+ //
+ // Update CertNumber.
+ //
+ CertBuf[0] = Index;
+
+ *SignerChainCerts = CertBuf;
+ *ChainLength = BufferSize;
+ }
+ }
+
+ if (CtxUntrusted != NULL) {
+ BufferSize = sizeof (UINT8);
+ CertBuf = NULL;
+
+ for (Index = 0; ; Index++) {
+ Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize);
+ if (!Status) {
+ break;
+ }
+
+ OldSize = BufferSize;
+ OldBuf = CertBuf;
+ BufferSize = OldSize + CertSize + sizeof (UINT32);
+ CertBuf = malloc (BufferSize);
+
+ if (CertBuf == NULL) {
+ Status = FALSE;
+ goto _Error;
+ }
+ if (OldBuf != NULL) {
+ CopyMem (CertBuf, OldBuf, OldSize);
+ free (OldBuf);
+ OldBuf = NULL;
+ }
+
+ WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
+ CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
+
+ free (SingleCert);
+ SingleCert = NULL;
+ }
+
+ if (CertBuf != NULL) {
+ //
+ // Update CertNumber.
+ //
+ CertBuf[0] = Index;
+
+ *UnchainCerts = CertBuf;
+ *UnchainLength = BufferSize;
+ }
+ }
+
+ Status = TRUE;
+
+_Error:
+ //
+ // Release Resources.
+ //
+ if (!Wrapped && (NewP7Data != NULL)) {
+ free (NewP7Data);
+ }
+
+ if (Pkcs7 != NULL) {
+ PKCS7_free (Pkcs7);
+ }
+ sk_X509_free (Signers);
+
+ if (CertCtx != NULL) {
+ X509_STORE_CTX_cleanup (CertCtx);
+ X509_STORE_CTX_free (CertCtx);
+ }
+
+ if (SingleCert != NULL) {
+ free (SingleCert);
+ }
+
+ if (OldBuf != NULL) {
+ free (OldBuf);
+ }
+
+ if (!Status && (CertBuf != NULL)) {
+ free (CertBuf);
+ *SignerChainCerts = NULL;
+ *UnchainCerts = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard". The input signed data could be wrapped
+ in a ContentInfo structure.
+
+ If P7Data, TrustedCert or InData is NULL, then return FALSE.
+ If P7Length, CertLength or DataLength overflow, then return FALSE.
+
+ Caution: This function may receive untrusted input.
+ UEFI Authenticated Variable is external input, so this function will do basic
+ check for PKCS#7 data structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 message to verify.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
+ is used for certificate chain verification.
+ @param[in] CertLength Length of the trusted certificate in bytes.
+ @param[in] InData Pointer to the content to be verified.
+ @param[in] DataLength Length of InData in bytes.
+
+ @retval TRUE The specified PKCS#7 signed data is valid.
+ @retval FALSE Invalid PKCS#7 signed data.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7Verify (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ IN CONST UINT8 *TrustedCert,
+ IN UINTN CertLength,
+ IN CONST UINT8 *InData,
+ IN UINTN DataLength
+ )
+{
+ PKCS7 *Pkcs7;
+ BIO *DataBio;
+ BOOLEAN Status;
+ X509 *Cert;
+ X509_STORE *CertStore;
+ UINT8 *SignedData;
+ CONST UINT8 *Temp;
+ UINTN SignedDataSize;
+ BOOLEAN Wrapped;
+
+ //
+ // Check input parameters.
+ //
+ if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||
+ P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {
+ return FALSE;
+ }
+
+ Pkcs7 = NULL;
+ DataBio = NULL;
+ Cert = NULL;
+ CertStore = NULL;
+
+ //
+ // Register & Initialize necessary digest algorithms for PKCS#7 Handling
+ //
+ if (EVP_add_digest (EVP_md5 ()) == 0) {
+ return FALSE;
+ }
+ if (EVP_add_digest (EVP_sha1 ()) == 0) {
+ return FALSE;
+ }
+ if (EVP_add_digest (EVP_sha256 ()) == 0) {
+ return FALSE;
+ }
+ if (EVP_add_digest (EVP_sha384 ()) == 0) {
+ return FALSE;
+ }
+ if (EVP_add_digest (EVP_sha512 ()) == 0) {
+ return FALSE;
+ }
+ if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
+ return FALSE;
+ }
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
+ if (!Status) {
+ return Status;
+ }
+
+ Status = FALSE;
+
+ //
+ // Retrieve PKCS#7 Data (DER encoding)
+ //
+ if (SignedDataSize > INT_MAX) {
+ goto _Exit;
+ }
+
+ Temp = SignedData;
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
+ //
+ if (!PKCS7_type_is_signed (Pkcs7)) {
+ goto _Exit;
+ }
+
+ //
+ // Read DER-encoded root certificate and Construct X509 Certificate
+ //
+ Temp = TrustedCert;
+ Cert = d2i_X509 (NULL, &Temp, (long) CertLength);
+ if (Cert == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Setup X509 Store for trusted certificate
+ //
+ CertStore = X509_STORE_new ();
+ if (CertStore == NULL) {
+ goto _Exit;
+ }
+ if (!(X509_STORE_add_cert (CertStore, Cert))) {
+ goto _Exit;
+ }
+
+ //
+ // For generic PKCS#7 handling, InData may be NULL if the content is present
+ // in PKCS#7 structure. So ignore NULL checking here.
+ //
+ DataBio = BIO_new (BIO_s_mem ());
+ if (DataBio == NULL) {
+ goto _Exit;
+ }
+
+ if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {
+ goto _Exit;
+ }
+
+ //
+ // Allow partial certificate chains, terminated by a non-self-signed but
+ // still trusted intermediate certificate. Also disable time checks.
+ //
+ X509_STORE_set_flags (CertStore,
+ X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
+
+ //
+ // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and
+ // doesn't support the extended key usage for Authenticode Code Signing.
+ // Bypass the certificate purpose checking by enabling any purposes setting.
+ //
+ X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
+
+ //
+ // Verifies the PKCS#7 signedData structure
+ //
+ Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);
+
+_Exit:
+ //
+ // Release Resources
+ //
+ BIO_free (DataBio);
+ X509_free (Cert);
+ X509_STORE_free (CertStore);
+ PKCS7_free (Pkcs7);
+
+ if (!Wrapped) {
+ OPENSSL_free (SignedData);
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c new file mode 100644 index 000000000..c9fdb65b9 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c @@ -0,0 +1,521 @@ +/** @file
+ This module verifies that Enhanced Key Usages (EKU's) are present within
+ a PKCS7 signature blob using OpenSSL.
+
+ Copyright (C) Microsoft Corporation. All Rights Reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include "InternalCryptLib.h"
+#include <openssl/x509v3.h>
+#include <openssl/asn1.h>
+#include <openssl/x509.h>
+#include <openssl/bio.h>
+#include <crypto/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/bn.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <crypto/asn1.h>
+
+/**
+ This function will return the leaf signer certificate in a chain. This is
+ required because certificate chains are not guaranteed to have the
+ certificates in the order that they were issued.
+
+ A typical certificate chain looks like this:
+
+
+ ----------------------------
+ | Root |
+ ----------------------------
+ ^
+ |
+ ----------------------------
+ | Policy CA | <-- Typical Trust Anchor.
+ ----------------------------
+ ^
+ |
+ ----------------------------
+ | Issuing CA |
+ ----------------------------
+ ^
+ |
+ -----------------------------
+ / End-Entity (leaf) signer / <-- Bottom certificate.
+ ----------------------------- EKU: "1.3.6.1.4.1.311.76.9.21.1"
+ (Firmware Signing)
+
+
+ @param[in] CertChain Certificate chain.
+
+ @param[out] SignerCert Last certificate in the chain. For PKCS7 signatures,
+ this will be the end-entity (leaf) signer cert.
+
+ @retval EFI_SUCCESS The required EKUs were found in the signature.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_NOT_FOUND The number of signers found was not 1.
+
+**/
+EFI_STATUS
+GetSignerCertificate (
+ IN CONST PKCS7 *CertChain,
+ OUT X509 **SignerCert
+ )
+{
+ EFI_STATUS Status;
+ STACK_OF(X509) *Signers;
+ INT32 NumberSigners;
+
+ Status = EFI_SUCCESS;
+ Signers = NULL;
+ NumberSigners = 0;
+
+ if (CertChain == NULL || SignerCert == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Get the signers from the chain.
+ //
+ Signers = PKCS7_get0_signers ((PKCS7*) CertChain, NULL, PKCS7_BINARY);
+ if (Signers == NULL) {
+ //
+ // Fail to get signers form PKCS7
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // There should only be one signer in the PKCS7 stack.
+ //
+ NumberSigners = sk_X509_num (Signers);
+ if (NumberSigners != 1) {
+ //
+ // The number of singers should have been 1
+ //
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ *SignerCert = sk_X509_value (Signers, 0);
+
+Exit:
+ //
+ // Release Resources
+ //
+ if (Signers != NULL) {
+ sk_X509_free (Signers);
+ }
+
+ return Status;
+}
+
+
+/**
+ Determines if the specified EKU represented in ASN1 form is present
+ in a given certificate.
+
+ @param[in] Cert The certificate to check.
+
+ @param[in] Asn1ToFind The EKU to look for.
+
+ @retval EFI_SUCCESS We successfully identified the signing type.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_NOT_FOUND One or more EKU's were not found in the signature.
+
+**/
+EFI_STATUS
+IsEkuInCertificate (
+ IN CONST X509 *Cert,
+ IN ASN1_OBJECT *Asn1ToFind
+ )
+{
+ EFI_STATUS Status;
+ X509 *ClonedCert;
+ X509_EXTENSION *Extension;
+ EXTENDED_KEY_USAGE *Eku;
+ INT32 ExtensionIndex;
+ INTN NumExtensions;
+ ASN1_OBJECT *Asn1InCert;
+ INTN Index;
+
+ Status = EFI_NOT_FOUND;
+ ClonedCert = NULL;
+ Extension = NULL;
+ Eku = NULL;
+ ExtensionIndex = -1;
+ NumExtensions = 0;
+ Asn1InCert = NULL;
+
+ if (Cert == NULL || Asn1ToFind == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Clone the certificate. This is required because the Extension API's
+ // only work once per instance of an X509 object.
+ //
+ ClonedCert = X509_dup ((X509*)Cert);
+ if (ClonedCert == NULL) {
+ //
+ // Fail to duplicate cert.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Look for the extended key usage.
+ //
+ ExtensionIndex = X509_get_ext_by_NID (ClonedCert, NID_ext_key_usage, -1);
+
+ if (ExtensionIndex < 0) {
+ //
+ // Fail to find 'NID_ext_key_usage' in Cert.
+ //
+ goto Exit;
+ }
+
+ Extension = X509_get_ext (ClonedCert, ExtensionIndex);
+ if (Extension == NULL) {
+ //
+ // Fail to get Extension form cert.
+ //
+ goto Exit;
+ }
+
+ Eku = (EXTENDED_KEY_USAGE*)X509V3_EXT_d2i (Extension);
+ if (Eku == NULL) {
+ //
+ // Fail to get Eku from extension.
+ //
+ goto Exit;
+ }
+
+ NumExtensions = sk_ASN1_OBJECT_num (Eku);
+
+ //
+ // Now loop through the extensions, looking for the specified Eku.
+ //
+ for (Index = 0; Index < NumExtensions; Index++) {
+ Asn1InCert = sk_ASN1_OBJECT_value (Eku, (INT32)Index);
+ if (Asn1InCert == NULL) {
+ //
+ // Fail to get ASN object from Eku.
+ //
+ goto Exit;
+ }
+
+ if (Asn1InCert->length == Asn1ToFind->length &&
+ CompareMem (Asn1InCert->data, Asn1ToFind->data, Asn1InCert->length) == 0) {
+ //
+ // Found Eku in certificate.
+ //
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+Exit:
+
+ //
+ // Release Resources
+ //
+ if (ClonedCert != NULL) {
+ X509_free (ClonedCert);
+ }
+
+ if (Eku != NULL) {
+ sk_ASN1_OBJECT_pop_free (Eku, ASN1_OBJECT_free);
+ }
+
+ return Status;
+}
+
+
+/**
+ Determines if the specified EKUs are present in a signing certificate.
+
+ @param[in] SignerCert The certificate to check.
+ @param[in] RequiredEKUs The EKUs to look for.
+ @param[in] RequiredEKUsSize The number of EKUs
+ @param[in] RequireAllPresent If TRUE, then all the specified EKUs
+ must be present in the certificate.
+
+ @retval EFI_SUCCESS We successfully identified the signing type.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_NOT_FOUND One or more EKU's were not found in the signature.
+**/
+EFI_STATUS
+CheckEKUs(
+ IN CONST X509 *SignerCert,
+ IN CONST CHAR8 *RequiredEKUs[],
+ IN CONST UINT32 RequiredEKUsSize,
+ IN BOOLEAN RequireAllPresent
+ )
+{
+ EFI_STATUS Status;
+ ASN1_OBJECT *Asn1ToFind;
+ UINT32 NumEkusFound;
+ UINT32 Index;
+
+ Status = EFI_SUCCESS;
+ Asn1ToFind = NULL;
+ NumEkusFound = 0;
+
+ if (SignerCert == NULL || RequiredEKUs == NULL || RequiredEKUsSize == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ for (Index = 0; Index < RequiredEKUsSize; Index++) {
+ //
+ // Finding required EKU in cert.
+ //
+ if (Asn1ToFind != NULL) {
+ ASN1_OBJECT_free(Asn1ToFind);
+ Asn1ToFind = NULL;
+ }
+
+ Asn1ToFind = OBJ_txt2obj (RequiredEKUs[Index], 0);
+ if (Asn1ToFind == NULL) {
+ //
+ // Fail to convert required EKU to ASN1.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = IsEkuInCertificate (SignerCert, Asn1ToFind);
+ if (Status == EFI_SUCCESS) {
+ NumEkusFound++;
+ if (!RequireAllPresent) {
+ //
+ // Found at least one, so we are done.
+ //
+ goto Exit;
+ }
+ } else {
+ //
+ // Fail to find Eku in cert
+ break;
+ }
+ }
+
+Exit:
+
+ if (Asn1ToFind != NULL) {
+ ASN1_OBJECT_free(Asn1ToFind);
+ }
+
+ if (RequireAllPresent &&
+ NumEkusFound == RequiredEKUsSize) {
+ //
+ // Found all required EKUs in certificate.
+ //
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ This function receives a PKCS#7 formatted signature blob,
+ looks for the EKU SEQUENCE blob, and if found then looks
+ for all the required EKUs. This function was created so that
+ the Surface team can cut down on the number of Certificate
+ Authorities (CA's) by checking EKU's on leaf signers for
+ a specific product. This prevents one product's certificate
+ from signing another product's firmware or unlock blobs.
+
+ Note that this function does not validate the certificate chain.
+ That needs to be done before using this function.
+
+ @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array
+ containing the content block with both the signature,
+ the signer's certificate, and any necessary intermediate
+ certificates.
+ @param[in] Pkcs7SignatureSize Number of bytes in Pkcs7Signature.
+ @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of
+ required EKUs that must be present in the signature.
+ @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs string array.
+ @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's
+ must be present in the leaf signer. If it is
+ FALSE, then we will succeed if we find any
+ of the specified EKU's.
+
+ @retval EFI_SUCCESS The required EKUs were found in the signature.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_NOT_FOUND One or more EKU's were not found in the signature.
+
+**/
+EFI_STATUS
+EFIAPI
+VerifyEKUsInPkcs7Signature (
+ IN CONST UINT8 *Pkcs7Signature,
+ IN CONST UINT32 SignatureSize,
+ IN CONST CHAR8 *RequiredEKUs[],
+ IN CONST UINT32 RequiredEKUsSize,
+ IN BOOLEAN RequireAllPresent
+ )
+{
+ EFI_STATUS Status;
+ PKCS7 *Pkcs7;
+ STACK_OF(X509) *CertChain;
+ INT32 SignatureType;
+ INT32 NumberCertsInSignature;
+ X509 *SignerCert;
+ UINT8 *SignedData;
+ UINT8 *Temp;
+ UINTN SignedDataSize;
+ BOOLEAN IsWrapped;
+ BOOLEAN Ok;
+
+ Status = EFI_SUCCESS;
+ Pkcs7 = NULL;
+ CertChain = NULL;
+ SignatureType = 0;
+ NumberCertsInSignature = 0;
+ SignerCert = NULL;
+ SignedData = NULL;
+ SignedDataSize = 0;
+ IsWrapped = FALSE;
+ Ok = FALSE;
+
+ //
+ //Validate the input parameters.
+ //
+ if (Pkcs7Signature == NULL ||
+ SignatureSize == 0 ||
+ RequiredEKUs == NULL ||
+ RequiredEKUsSize == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (RequiredEKUsSize == 1) {
+ RequireAllPresent = TRUE;
+ }
+
+ //
+ // Wrap the PKCS7 data if needed.
+ //
+ Ok = WrapPkcs7Data (Pkcs7Signature,
+ SignatureSize,
+ &IsWrapped,
+ &SignedData,
+ &SignedDataSize);
+ if (!Ok) {
+ //
+ // Fail to Wrap the PKCS7 data.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Temp = SignedData;
+
+ //
+ // Create the PKCS7 object.
+ //
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (INT32)SignedDataSize);
+ if (Pkcs7 == NULL) {
+ //
+ // Fail to read PKCS7 data.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Get the certificate chain.
+ //
+ SignatureType = OBJ_obj2nid (Pkcs7->type);
+ switch (SignatureType) {
+ case NID_pkcs7_signed:
+ if (Pkcs7->d.sign != NULL) {
+ CertChain = Pkcs7->d.sign->cert;
+ }
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ if (Pkcs7->d.signed_and_enveloped != NULL) {
+ CertChain = Pkcs7->d.signed_and_enveloped->cert;
+ }
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Ensure we have a certificate stack
+ //
+ if (CertChain == NULL) {
+ //
+ // Fail to get the certificate stack from signature.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Find out how many certificates were in the PKCS7 signature.
+ //
+ NumberCertsInSignature = sk_X509_num (CertChain);
+
+ if (NumberCertsInSignature == 0) {
+ //
+ // Fail to find any certificates in signature.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Get the leaf signer.
+ //
+ Status = GetSignerCertificate (Pkcs7, &SignerCert);
+ if (Status != EFI_SUCCESS || SignerCert == NULL) {
+ //
+ // Fail to get the end-entity leaf signer certificate.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = CheckEKUs (SignerCert, RequiredEKUs, RequiredEKUsSize, RequireAllPresent);
+ if (Status != EFI_SUCCESS) {
+ goto Exit;
+ }
+
+Exit:
+
+ //
+ // Release Resources
+ //
+ // If the signature was not wrapped, then the call to WrapData() will allocate
+ // the data and add a header to it
+ //
+ if (!IsWrapped && SignedData) {
+ free (SignedData);
+ }
+
+ if (SignerCert != NULL) {
+ X509_free (SignerCert);
+ }
+
+ if (Pkcs7 != NULL) {
+ PKCS7_free (Pkcs7);
+ }
+
+ return Status;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c new file mode 100644 index 000000000..aea5d30a6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c @@ -0,0 +1,57 @@ +/** @file
+ This module verifies that Enhanced Key Usages (EKU's) are present within
+ a PKCS7 signature blob using OpenSSL.
+
+ Copyright (C) Microsoft Corporation. All Rights Reserved.
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ This function receives a PKCS#7 formatted signature blob,
+ looks for the EKU SEQUENCE blob, and if found then looks
+ for all the required EKUs. This function was created so that
+ the Surface team can cut down on the number of Certificate
+ Authorities (CA's) by checking EKU's on leaf signers for
+ a specific product. This prevents one product's certificate
+ from signing another product's firmware or unlock blobs.
+
+ Return RETURN_UNSUPPORTED to indicate this interface is not supported.
+
+ @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array
+ containing the content block with both the signature,
+ the signer's certificate, and any necessary intermediate
+ certificates.
+ @param[in] Pkcs7SignatureSize Number of bytes in pPkcs7Signature.
+ @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of
+ required EKUs that must be present in the signature.
+ All specified EKU's must be present in order to
+ succeed.
+ @param[in] RequiredEKUsSize Number of elements in the rgRequiredEKUs string.
+ This parameter has a maximum of MAX_EKU_SEARCH.
+ @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's
+ must be present in the leaf signer. If it is
+ FALSE, then we will succeed if we find any
+ of the specified EKU's.
+
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+VerifyEKUsInPkcs7Signature (
+ IN CONST UINT8 *Pkcs7Signature,
+ IN CONST UINT32 SignatureSize,
+ IN CONST CHAR8 *RequiredEKUs[],
+ IN CONST UINT32 RequiredEKUsSize,
+ IN BOOLEAN RequireAllPresent
+ )
+{
+ ASSERT (FALSE);
+ return RETURN_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c new file mode 100644 index 000000000..0ddf16a61 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c @@ -0,0 +1,163 @@ +/** @file
+ PKCS#7 SignedData Verification Wrapper Implementation which does not provide
+ real capabilities.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard". The input signed data could be wrapped
+ in a ContentInfo structure.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] P7Data Pointer to the PKCS#7 message to verify.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.
+ It's caller's responsibility to free the buffer with
+ Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] StackLength Length of signer's certificates in bytes.
+ @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.
+ It's caller's responsibility to free the buffer with
+ Pkcs7FreeSigners().
+ @param[out] CertLength Length of the trusted certificate in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetSigners (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT UINT8 **CertStack,
+ OUT UINTN *StackLength,
+ OUT UINT8 **TrustedCert,
+ OUT UINTN *CertLength
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Wrap function to use free() to free allocated memory for certificates.
+
+ If the interface is not supported, then ASSERT().
+
+ @param[in] Certs Pointer to the certificates to be freed.
+
+**/
+VOID
+EFIAPI
+Pkcs7FreeSigners (
+ IN UINT8 *Certs
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard", and outputs two certificate lists chained and
+ unchained to the signer's certificates.
+ The input signed data could be wrapped in a ContentInfo structure.
+
+ @param[in] P7Data Pointer to the PKCS#7 message.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[out] SignerChainCerts Pointer to the certificates list chained to signer's
+ certificate. It's caller's responsibility to free the buffer
+ with Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] ChainLength Length of the chained certificates list buffer in bytes.
+ @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's
+ responsibility to free the buffer with Pkcs7FreeSigners().
+ This data structure is EFI_CERT_STACK type.
+ @param[out] UnchainLength Length of the unchained certificates list buffer in bytes.
+
+ @retval TRUE The operation is finished successfully.
+ @retval FALSE Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT UINT8 **SignerChainCerts,
+ OUT UINTN *ChainLength,
+ OUT UINT8 **UnchainCerts,
+ OUT UINTN *UnchainLength
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:
+ Cryptographic Message Syntax Standard". The input signed data could be wrapped
+ in a ContentInfo structure.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] P7Data Pointer to the PKCS#7 message to verify.
+ @param[in] P7Length Length of the PKCS#7 message in bytes.
+ @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
+ is used for certificate chain verification.
+ @param[in] CertLength Length of the trusted certificate in bytes.
+ @param[in] InData Pointer to the content to be verified.
+ @param[in] DataLength Length of InData in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7Verify (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ IN CONST UINT8 *TrustedCert,
+ IN UINTN CertLength,
+ IN CONST UINT8 *InData,
+ IN UINTN DataLength
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Extracts the attached content from a PKCS#7 signed data if existed. The input signed
+ data could be wrapped in a ContentInfo structure.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] P7Data Pointer to the PKCS#7 signed data to process.
+ @param[in] P7Length Length of the PKCS#7 signed data in bytes.
+ @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.
+ It's caller's responsibility to free the buffer with FreePool().
+ @param[out] ContentSize The size of the extracted content in bytes.
+
+ @retval TRUE The P7Data was correctly formatted for processing.
+ @retval FALSE The P7Data was not correctly formatted for processing.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetAttachedContent (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT VOID **Content,
+ OUT UINTN *ContentSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c new file mode 100644 index 000000000..1b0cda182 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c @@ -0,0 +1,39 @@ +/** @file
+ Runtime specific implementation of PKCS#7 SignedData Verification Wrapper.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Extracts the attached content from a PKCS#7 signed data if existed. The input signed
+ data could be wrapped in a ContentInfo structure.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] P7Data Pointer to the PKCS#7 signed data to process.
+ @param[in] P7Length Length of the PKCS#7 signed data in bytes.
+ @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.
+ It's caller's responsibility to free the buffer with FreePool().
+ @param[out] ContentSize The size of the extracted content in bytes.
+
+ @retval TRUE The P7Data was correctly formatted for processing.
+ @retval FALSE The P7Data was not correctly formatted for processing.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetAttachedContent (
+ IN CONST UINT8 *P7Data,
+ IN UINTN P7Length,
+ OUT VOID **Content,
+ OUT UINTN *ContentSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c new file mode 100644 index 000000000..d24e1fdf6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c @@ -0,0 +1,327 @@ +/** @file
+ RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
+
+ This file implements following APIs which provide basic capabilities for RSA:
+ 1) RsaNew
+ 2) RsaFree
+ 3) RsaSetKey
+ 4) RsaPkcs1Verify
+
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/objects.h>
+
+/**
+ Allocates and initializes one RSA context for subsequent use.
+
+ @return Pointer to the RSA context that has been initialized.
+ If the allocations fails, RsaNew() returns NULL.
+
+**/
+VOID *
+EFIAPI
+RsaNew (
+ VOID
+ )
+{
+ //
+ // Allocates & Initializes RSA Context by OpenSSL RSA_new()
+ //
+ return (VOID *) RSA_new ();
+}
+
+/**
+ Release the specified RSA context.
+
+ @param[in] RsaContext Pointer to the RSA context to be released.
+
+**/
+VOID
+EFIAPI
+RsaFree (
+ IN VOID *RsaContext
+ )
+{
+ //
+ // Free OpenSSL RSA Context
+ //
+ RSA_free ((RSA *) RsaContext);
+}
+
+/**
+ Sets the tag-designated key component into the established RSA context.
+
+ This function sets the tag-designated RSA key component into the established
+ RSA context from the user-specified non-negative integer (octet string format
+ represented in RSA PKCS#1).
+ If BigNumber is NULL, then the specified key component in RSA context is cleared.
+
+ If RsaContext is NULL, then return FALSE.
+
+ @param[in, out] RsaContext Pointer to RSA context being set.
+ @param[in] KeyTag Tag of RSA key component being set.
+ @param[in] BigNumber Pointer to octet integer buffer.
+ If NULL, then the specified key component in RSA
+ context is cleared.
+ @param[in] BnSize Size of big number buffer in bytes.
+ If BigNumber is NULL, then it is ignored.
+
+ @retval TRUE RSA key component was set successfully.
+ @retval FALSE Invalid RSA key component tag.
+
+**/
+BOOLEAN
+EFIAPI
+RsaSetKey (
+ IN OUT VOID *RsaContext,
+ IN RSA_KEY_TAG KeyTag,
+ IN CONST UINT8 *BigNumber,
+ IN UINTN BnSize
+ )
+{
+ RSA *RsaKey;
+ BIGNUM *BnN;
+ BIGNUM *BnE;
+ BIGNUM *BnD;
+ BIGNUM *BnP;
+ BIGNUM *BnQ;
+ BIGNUM *BnDp;
+ BIGNUM *BnDq;
+ BIGNUM *BnQInv;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL || BnSize > INT_MAX) {
+ return FALSE;
+ }
+
+ BnN = NULL;
+ BnE = NULL;
+ BnD = NULL;
+ BnP = NULL;
+ BnQ = NULL;
+ BnDp = NULL;
+ BnDq = NULL;
+ BnQInv = NULL;
+
+ //
+ // Retrieve the components from RSA object.
+ //
+ RsaKey = (RSA *) RsaContext;
+ RSA_get0_key (RsaKey, (const BIGNUM **)&BnN, (const BIGNUM **)&BnE, (const BIGNUM **)&BnD);
+ RSA_get0_factors (RsaKey, (const BIGNUM **)&BnP, (const BIGNUM **)&BnQ);
+ RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnDp, (const BIGNUM **)&BnDq, (const BIGNUM **)&BnQInv);
+
+ //
+ // Set RSA Key Components by converting octet string to OpenSSL BN representation.
+ // NOTE: For RSA public key (used in signature verification), only public components
+ // (N, e) are needed.
+ //
+ switch (KeyTag) {
+
+ //
+ // RSA Public Modulus (N), Public Exponent (e) and Private Exponent (d)
+ //
+ case RsaKeyN:
+ case RsaKeyE:
+ case RsaKeyD:
+ if (BnN == NULL) {
+ BnN = BN_new ();
+ }
+ if (BnE == NULL) {
+ BnE = BN_new ();
+ }
+ if (BnD == NULL) {
+ BnD = BN_new ();
+ }
+
+ if ((BnN == NULL) || (BnE == NULL) || (BnD == NULL)) {
+ return FALSE;
+ }
+
+ switch (KeyTag) {
+ case RsaKeyN:
+ BnN = BN_bin2bn (BigNumber, (UINT32)BnSize, BnN);
+ break;
+ case RsaKeyE:
+ BnE = BN_bin2bn (BigNumber, (UINT32)BnSize, BnE);
+ break;
+ case RsaKeyD:
+ BnD = BN_bin2bn (BigNumber, (UINT32)BnSize, BnD);
+ break;
+ default:
+ return FALSE;
+ }
+ if (RSA_set0_key (RsaKey, BN_dup(BnN), BN_dup(BnE), BN_dup(BnD)) == 0) {
+ return FALSE;
+ }
+
+ break;
+
+ //
+ // RSA Secret Prime Factor of Modulus (p and q)
+ //
+ case RsaKeyP:
+ case RsaKeyQ:
+ if (BnP == NULL) {
+ BnP = BN_new ();
+ }
+ if (BnQ == NULL) {
+ BnQ = BN_new ();
+ }
+ if ((BnP == NULL) || (BnQ == NULL)) {
+ return FALSE;
+ }
+
+ switch (KeyTag) {
+ case RsaKeyP:
+ BnP = BN_bin2bn (BigNumber, (UINT32)BnSize, BnP);
+ break;
+ case RsaKeyQ:
+ BnQ = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQ);
+ break;
+ default:
+ return FALSE;
+ }
+ if (RSA_set0_factors (RsaKey, BN_dup(BnP), BN_dup(BnQ)) == 0) {
+ return FALSE;
+ }
+
+ break;
+
+ //
+ // p's CRT Exponent (== d mod (p - 1)), q's CRT Exponent (== d mod (q - 1)),
+ // and CRT Coefficient (== 1/q mod p)
+ //
+ case RsaKeyDp:
+ case RsaKeyDq:
+ case RsaKeyQInv:
+ if (BnDp == NULL) {
+ BnDp = BN_new ();
+ }
+ if (BnDq == NULL) {
+ BnDq = BN_new ();
+ }
+ if (BnQInv == NULL) {
+ BnQInv = BN_new ();
+ }
+ if ((BnDp == NULL) || (BnDq == NULL) || (BnQInv == NULL)) {
+ return FALSE;
+ }
+
+ switch (KeyTag) {
+ case RsaKeyDp:
+ BnDp = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDp);
+ break;
+ case RsaKeyDq:
+ BnDq = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDq);
+ break;
+ case RsaKeyQInv:
+ BnQInv = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQInv);
+ break;
+ default:
+ return FALSE;
+ }
+ if (RSA_set0_crt_params (RsaKey, BN_dup(BnDp), BN_dup(BnDq), BN_dup(BnQInv)) == 0) {
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in
+ RSA PKCS#1.
+
+ If RsaContext is NULL, then return FALSE.
+ If MessageHash is NULL, then return FALSE.
+ If Signature is NULL, then return FALSE.
+ If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE.
+
+ @param[in] RsaContext Pointer to RSA context for signature verification.
+ @param[in] MessageHash Pointer to octet message hash to be checked.
+ @param[in] HashSize Size of the message hash in bytes.
+ @param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.
+ @param[in] SigSize Size of signature in bytes.
+
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.
+ @retval FALSE Invalid signature or invalid RSA context.
+
+**/
+BOOLEAN
+EFIAPI
+RsaPkcs1Verify (
+ IN VOID *RsaContext,
+ IN CONST UINT8 *MessageHash,
+ IN UINTN HashSize,
+ IN CONST UINT8 *Signature,
+ IN UINTN SigSize
+ )
+{
+ INT32 DigestType;
+ UINT8 *SigBuf;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) {
+ return FALSE;
+ }
+
+ if (SigSize > INT_MAX || SigSize == 0) {
+ return FALSE;
+ }
+
+ //
+ // Determine the message digest algorithm according to digest size.
+ // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported.
+ //
+ switch (HashSize) {
+ case MD5_DIGEST_SIZE:
+ DigestType = NID_md5;
+ break;
+
+ case SHA1_DIGEST_SIZE:
+ DigestType = NID_sha1;
+ break;
+
+ case SHA256_DIGEST_SIZE:
+ DigestType = NID_sha256;
+ break;
+
+ case SHA384_DIGEST_SIZE:
+ DigestType = NID_sha384;
+ break;
+
+ case SHA512_DIGEST_SIZE:
+ DigestType = NID_sha512;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ SigBuf = (UINT8 *) Signature;
+ return (BOOLEAN) RSA_verify (
+ DigestType,
+ MessageHash,
+ (UINT32) HashSize,
+ SigBuf,
+ (UINT32) SigSize,
+ (RSA *) RsaContext
+ );
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c new file mode 100644 index 000000000..7cd5fecf0 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c @@ -0,0 +1,364 @@ +/** @file
+ RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
+
+ This file implements following APIs which provide more capabilities for RSA:
+ 1) RsaGetKey
+ 2) RsaGenerateKey
+ 3) RsaCheckKey
+ 4) RsaPkcs1Sign
+
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+#include <openssl/objects.h>
+
+/**
+ Gets the tag-designated RSA key component from the established RSA context.
+
+ This function retrieves the tag-designated RSA key component from the
+ established RSA context as a non-negative integer (octet string format
+ represented in RSA PKCS#1).
+ If specified key component has not been set or has been cleared, then returned
+ BnSize is set to 0.
+ If the BigNumber buffer is too small to hold the contents of the key, FALSE
+ is returned and BnSize is set to the required buffer size to obtain the key.
+
+ If RsaContext is NULL, then return FALSE.
+ If BnSize is NULL, then return FALSE.
+ If BnSize is large enough but BigNumber is NULL, then return FALSE.
+
+ @param[in, out] RsaContext Pointer to RSA context being set.
+ @param[in] KeyTag Tag of RSA key component being set.
+ @param[out] BigNumber Pointer to octet integer buffer.
+ @param[in, out] BnSize On input, the size of big number buffer in bytes.
+ On output, the size of data returned in big number buffer in bytes.
+
+ @retval TRUE RSA key component was retrieved successfully.
+ @retval FALSE Invalid RSA key component tag.
+ @retval FALSE BnSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGetKey (
+ IN OUT VOID *RsaContext,
+ IN RSA_KEY_TAG KeyTag,
+ OUT UINT8 *BigNumber,
+ IN OUT UINTN *BnSize
+ )
+{
+ RSA *RsaKey;
+ BIGNUM *BnKey;
+ UINTN Size;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL || BnSize == NULL) {
+ return FALSE;
+ }
+
+ RsaKey = (RSA *) RsaContext;
+ Size = *BnSize;
+ *BnSize = 0;
+ BnKey = NULL;
+
+ switch (KeyTag) {
+
+ //
+ // RSA Public Modulus (N)
+ //
+ case RsaKeyN:
+ RSA_get0_key (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL);
+ break;
+
+ //
+ // RSA Public Exponent (e)
+ //
+ case RsaKeyE:
+ RSA_get0_key (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL);
+ break;
+
+ //
+ // RSA Private Exponent (d)
+ //
+ case RsaKeyD:
+ RSA_get0_key (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey);
+ break;
+
+ //
+ // RSA Secret Prime Factor of Modulus (p)
+ //
+ case RsaKeyP:
+ RSA_get0_factors (RsaKey, (const BIGNUM **)&BnKey, NULL);
+ break;
+
+ //
+ // RSA Secret Prime Factor of Modules (q)
+ //
+ case RsaKeyQ:
+ RSA_get0_factors (RsaKey, NULL, (const BIGNUM **)&BnKey);
+ break;
+
+ //
+ // p's CRT Exponent (== d mod (p - 1))
+ //
+ case RsaKeyDp:
+ RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL);
+ break;
+
+ //
+ // q's CRT Exponent (== d mod (q - 1))
+ //
+ case RsaKeyDq:
+ RSA_get0_crt_params (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL);
+ break;
+
+ //
+ // The CRT Coefficient (== 1/q mod p)
+ //
+ case RsaKeyQInv:
+ RSA_get0_crt_params (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ if (BnKey == NULL) {
+ return FALSE;
+ }
+
+ *BnSize = Size;
+ Size = BN_num_bytes (BnKey);
+
+ if (*BnSize < Size) {
+ *BnSize = Size;
+ return FALSE;
+ }
+
+ if (BigNumber == NULL) {
+ *BnSize = Size;
+ return TRUE;
+ }
+ *BnSize = BN_bn2bin (BnKey, BigNumber) ;
+
+ return TRUE;
+}
+
+/**
+ Generates RSA key components.
+
+ This function generates RSA key components. It takes RSA public exponent E and
+ length in bits of RSA modulus N as input, and generates all key components.
+ If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used.
+
+ Before this function can be invoked, pseudorandom number generator must be correctly
+ initialized by RandomSeed().
+
+ If RsaContext is NULL, then return FALSE.
+
+ @param[in, out] RsaContext Pointer to RSA context being set.
+ @param[in] ModulusLength Length of RSA modulus N in bits.
+ @param[in] PublicExponent Pointer to RSA public exponent.
+ @param[in] PublicExponentSize Size of RSA public exponent buffer in bytes.
+
+ @retval TRUE RSA key component was generated successfully.
+ @retval FALSE Invalid RSA key component tag.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGenerateKey (
+ IN OUT VOID *RsaContext,
+ IN UINTN ModulusLength,
+ IN CONST UINT8 *PublicExponent,
+ IN UINTN PublicExponentSize
+ )
+{
+ BIGNUM *KeyE;
+ BOOLEAN RetVal;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL || ModulusLength > INT_MAX || PublicExponentSize > INT_MAX) {
+ return FALSE;
+ }
+
+ KeyE = BN_new ();
+ if (KeyE == NULL) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+
+ if (PublicExponent == NULL) {
+ if (BN_set_word (KeyE, 0x10001) == 0) {
+ goto _Exit;
+ }
+ } else {
+ if (BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE) == NULL) {
+ goto _Exit;
+ }
+ }
+
+ if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {
+ RetVal = TRUE;
+ }
+
+_Exit:
+ BN_free (KeyE);
+ return RetVal;
+}
+
+/**
+ Validates key components of RSA context.
+ NOTE: This function performs integrity checks on all the RSA key material, so
+ the RSA key structure must contain all the private key data.
+
+ This function validates key components of RSA context in following aspects:
+ - Whether p is a prime
+ - Whether q is a prime
+ - Whether n = p * q
+ - Whether d*e = 1 mod lcm(p-1,q-1)
+
+ If RsaContext is NULL, then return FALSE.
+
+ @param[in] RsaContext Pointer to RSA context to check.
+
+ @retval TRUE RSA key components are valid.
+ @retval FALSE RSA key components are not valid.
+
+**/
+BOOLEAN
+EFIAPI
+RsaCheckKey (
+ IN VOID *RsaContext
+ )
+{
+ UINTN Reason;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL) {
+ return FALSE;
+ }
+
+ if (RSA_check_key ((RSA *) RsaContext) != 1) {
+ Reason = ERR_GET_REASON (ERR_peek_last_error ());
+ if (Reason == RSA_R_P_NOT_PRIME ||
+ Reason == RSA_R_Q_NOT_PRIME ||
+ Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||
+ Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.
+
+ This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in
+ RSA PKCS#1.
+ If the Signature buffer is too small to hold the contents of signature, FALSE
+ is returned and SigSize is set to the required buffer size to obtain the signature.
+
+ If RsaContext is NULL, then return FALSE.
+ If MessageHash is NULL, then return FALSE.
+ If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE.
+ If SigSize is large enough but Signature is NULL, then return FALSE.
+
+ @param[in] RsaContext Pointer to RSA context for signature generation.
+ @param[in] MessageHash Pointer to octet message hash to be signed.
+ @param[in] HashSize Size of the message hash in bytes.
+ @param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature.
+ @param[in, out] SigSize On input, the size of Signature buffer in bytes.
+ On output, the size of data returned in Signature buffer in bytes.
+
+ @retval TRUE Signature successfully generated in PKCS1-v1_5.
+ @retval FALSE Signature generation failed.
+ @retval FALSE SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+RsaPkcs1Sign (
+ IN VOID *RsaContext,
+ IN CONST UINT8 *MessageHash,
+ IN UINTN HashSize,
+ OUT UINT8 *Signature,
+ IN OUT UINTN *SigSize
+ )
+{
+ RSA *Rsa;
+ UINTN Size;
+ INT32 DigestType;
+
+ //
+ // Check input parameters.
+ //
+ if (RsaContext == NULL || MessageHash == NULL) {
+ return FALSE;
+ }
+
+ Rsa = (RSA *) RsaContext;
+ Size = RSA_size (Rsa);
+
+ if (*SigSize < Size) {
+ *SigSize = Size;
+ return FALSE;
+ }
+
+ if (Signature == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Determine the message digest algorithm according to digest size.
+ // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported.
+ //
+ switch (HashSize) {
+ case MD5_DIGEST_SIZE:
+ DigestType = NID_md5;
+ break;
+
+ case SHA1_DIGEST_SIZE:
+ DigestType = NID_sha1;
+ break;
+
+ case SHA256_DIGEST_SIZE:
+ DigestType = NID_sha256;
+ break;
+
+ case SHA384_DIGEST_SIZE:
+ DigestType = NID_sha384;
+ break;
+
+ case SHA512_DIGEST_SIZE:
+ DigestType = NID_sha512;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return (BOOLEAN) RSA_sign (
+ DigestType,
+ MessageHash,
+ (UINT32) HashSize,
+ Signature,
+ (UINT32 *) SigSize,
+ (RSA *) RsaContext
+ );
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c new file mode 100644 index 000000000..260cb00e6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c @@ -0,0 +1,119 @@ +/** @file
+ RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
+
+ This file does not provide real capabilities for following APIs in RSA handling:
+ 1) RsaGetKey
+ 2) RsaGenerateKey
+ 3) RsaCheckKey
+ 4) RsaPkcs1Sign
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Gets the tag-designated RSA key component from the established RSA context.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] RsaContext Pointer to RSA context being set.
+ @param[in] KeyTag Tag of RSA key component being set.
+ @param[out] BigNumber Pointer to octet integer buffer.
+ @param[in, out] BnSize On input, the size of big number buffer in bytes.
+ On output, the size of data returned in big number buffer in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGetKey (
+ IN OUT VOID *RsaContext,
+ IN RSA_KEY_TAG KeyTag,
+ OUT UINT8 *BigNumber,
+ IN OUT UINTN *BnSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Generates RSA key components.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] RsaContext Pointer to RSA context being set.
+ @param[in] ModulusLength Length of RSA modulus N in bits.
+ @param[in] PublicExponent Pointer to RSA public exponent.
+ @param[in] PublicExponentSize Size of RSA public exponent buffer in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGenerateKey (
+ IN OUT VOID *RsaContext,
+ IN UINTN ModulusLength,
+ IN CONST UINT8 *PublicExponent,
+ IN UINTN PublicExponentSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Validates key components of RSA context.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] RsaContext Pointer to RSA context to check.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+RsaCheckKey (
+ IN VOID *RsaContext
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] RsaContext Pointer to RSA context for signature generation.
+ @param[in] MessageHash Pointer to octet message hash to be signed.
+ @param[in] HashSize Size of the message hash in bytes.
+ @param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature.
+ @param[in, out] SigSize On input, the size of Signature buffer in bytes.
+ On output, the size of data returned in Signature buffer in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+RsaPkcs1Sign (
+ IN VOID *RsaContext,
+ IN CONST UINT8 *MessageHash,
+ IN UINTN HashSize,
+ OUT UINT8 *Signature,
+ IN OUT UINTN *SigSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c new file mode 100644 index 000000000..ff7f6488f --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c @@ -0,0 +1,659 @@ +/** @file
+ RFC3161 Timestamp Countersignature Verification over OpenSSL.
+ The timestamp is generated by a TimeStamping Authority (TSA) and asserts that a
+ publisher's signature existed before the specified time. The timestamp extends
+ the lifetime of the signature when a signing certificate expires or is later
+ revoked.
+
+Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pkcs7.h>
+
+//
+// OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1")
+//
+UINT8 mSpcRFC3161OidValue[] = {
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01
+ };
+
+///
+/// The messageImprint field SHOULD contain the hash of the datum to be
+/// time-stamped. The hash is represented as an OCTET STRING. Its
+/// length MUST match the length of the hash value for that algorithm
+/// (e.g., 20 bytes for SHA-1 or 16 bytes for MD5).
+///
+/// MessageImprint ::= SEQUENCE {
+/// hashAlgorithm AlgorithmIdentifier,
+/// hashedMessage OCTET STRING }
+///
+typedef struct {
+ X509_ALGOR *HashAlgorithm;
+ ASN1_OCTET_STRING *HashedMessage;
+} TS_MESSAGE_IMPRINT;
+
+//
+// ASN.1 Functions for TS_MESSAGE_IMPRINT
+//
+DECLARE_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
+ASN1_SEQUENCE (TS_MESSAGE_IMPRINT) = {
+ ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashedMessage, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END (TS_MESSAGE_IMPRINT)
+IMPLEMENT_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
+
+///
+/// Accuracy represents the time deviation around the UTC time contained
+/// in GeneralizedTime of time-stamp token.
+///
+/// Accuracy ::= SEQUENCE {
+/// seconds INTEGER OPTIONAL,
+/// millis [0] INTEGER (1..999) OPTIONAL,
+/// micros [1] INTEGER (1..999) OPTIONAL }
+///
+typedef struct {
+ ASN1_INTEGER *Seconds;
+ ASN1_INTEGER *Millis;
+ ASN1_INTEGER *Micros;
+} TS_ACCURACY;
+
+//
+// ASN.1 Functions for TS_ACCURACY
+//
+DECLARE_ASN1_FUNCTIONS (TS_ACCURACY)
+ASN1_SEQUENCE (TS_ACCURACY) = {
+ ASN1_OPT (TS_ACCURACY, Seconds, ASN1_INTEGER),
+ ASN1_IMP_OPT (TS_ACCURACY, Millis, ASN1_INTEGER, 0),
+ ASN1_IMP_OPT (TS_ACCURACY, Micros, ASN1_INTEGER, 1)
+} ASN1_SEQUENCE_END (TS_ACCURACY)
+IMPLEMENT_ASN1_FUNCTIONS (TS_ACCURACY)
+
+///
+/// The timestamp token info resulting from a successful timestamp request,
+/// as defined in RFC 3161.
+///
+/// TSTInfo ::= SEQUENCE {
+/// version INTEGER { v1(1) },
+/// policy TSAPolicyId,
+/// messageImprint MessageImprint,
+/// -- MUST have the same value as the similar field in
+/// -- TimeStampReq
+/// serialNumber INTEGER,
+/// -- Time-Stamping users MUST be ready to accommodate integers
+/// -- up to 160 bits.
+/// genTime GeneralizedTime,
+/// accuracy Accuracy OPTIONAL,
+/// ordering BOOLEAN DEFAULT FALSE,
+/// nonce INTEGER OPTIONAL,
+/// -- MUST be present if the similar field was present
+/// -- in TimeStampReq. In that case it MUST have the same value.
+/// tsa [0] GeneralName OPTIONAL,
+/// extensions [1] IMPLICIT Extensions OPTIONAL }
+///
+typedef struct {
+ ASN1_INTEGER *Version;
+ ASN1_OBJECT *Policy;
+ TS_MESSAGE_IMPRINT *MessageImprint;
+ ASN1_INTEGER *SerialNumber;
+ ASN1_GENERALIZEDTIME *GenTime;
+ TS_ACCURACY *Accuracy;
+ ASN1_BOOLEAN Ordering;
+ ASN1_INTEGER *Nonce;
+ GENERAL_NAME *Tsa;
+ STACK_OF(X509_EXTENSION) *Extensions;
+} TS_TST_INFO;
+
+//
+// ASN.1 Functions for TS_TST_INFO
+//
+DECLARE_ASN1_FUNCTIONS (TS_TST_INFO)
+ASN1_SEQUENCE (TS_TST_INFO) = {
+ ASN1_SIMPLE (TS_TST_INFO, Version, ASN1_INTEGER),
+ ASN1_SIMPLE (TS_TST_INFO, Policy, ASN1_OBJECT),
+ ASN1_SIMPLE (TS_TST_INFO, MessageImprint, TS_MESSAGE_IMPRINT),
+ ASN1_SIMPLE (TS_TST_INFO, SerialNumber, ASN1_INTEGER),
+ ASN1_SIMPLE (TS_TST_INFO, GenTime, ASN1_GENERALIZEDTIME),
+ ASN1_OPT (TS_TST_INFO, Accuracy, TS_ACCURACY),
+ ASN1_OPT (TS_TST_INFO, Ordering, ASN1_FBOOLEAN),
+ ASN1_OPT (TS_TST_INFO, Nonce, ASN1_INTEGER),
+ ASN1_EXP_OPT(TS_TST_INFO, Tsa, GENERAL_NAME, 0),
+ ASN1_IMP_SEQUENCE_OF_OPT (TS_TST_INFO, Extensions, X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END (TS_TST_INFO)
+IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO)
+
+
+/**
+ Convert ASN.1 GeneralizedTime to EFI Time.
+
+ @param[in] Asn1Time Pointer to the ASN.1 GeneralizedTime to be converted.
+ @param[out] SigningTime Return the corresponding EFI Time.
+
+ @retval TRUE The time conversion succeeds.
+ @retval FALSE Invalid parameters.
+
+**/
+BOOLEAN
+EFIAPI
+ConvertAsn1TimeToEfiTime (
+ IN ASN1_TIME *Asn1Time,
+ OUT EFI_TIME *EfiTime
+ )
+{
+ CONST CHAR8 *Str;
+ UINTN Index;
+
+ if ((Asn1Time == NULL) || (EfiTime == NULL)) {
+ return FALSE;
+ }
+
+ Str = (CONST CHAR8*)Asn1Time->data;
+ SetMem (EfiTime, 0, sizeof (EFI_TIME));
+
+ Index = 0;
+ if (Asn1Time->type == V_ASN1_UTCTIME) { /* two digit year */
+ EfiTime->Year = (Str[Index++] - '0') * 10;
+ EfiTime->Year += (Str[Index++] - '0');
+ if (EfiTime->Year < 70) {
+ EfiTime->Year += 100;
+ }
+ } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */
+ EfiTime->Year = (Str[Index++] - '0') * 1000;
+ EfiTime->Year += (Str[Index++] - '0') * 100;
+ EfiTime->Year += (Str[Index++] - '0') * 10;
+ EfiTime->Year += (Str[Index++] - '0');
+ if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) {
+ return FALSE;
+ }
+ }
+
+ EfiTime->Month = (Str[Index++] - '0') * 10;
+ EfiTime->Month += (Str[Index++] - '0');
+ if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) {
+ return FALSE;
+ }
+
+ EfiTime->Day = (Str[Index++] - '0') * 10;
+ EfiTime->Day += (Str[Index++] - '0');
+ if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) {
+ return FALSE;
+ }
+
+ EfiTime->Hour = (Str[Index++] - '0') * 10;
+ EfiTime->Hour += (Str[Index++] - '0');
+ if (EfiTime->Hour > 23) {
+ return FALSE;
+ }
+
+ EfiTime->Minute = (Str[Index++] - '0') * 10;
+ EfiTime->Minute += (Str[Index++] - '0');
+ if (EfiTime->Minute > 59) {
+ return FALSE;
+ }
+
+ EfiTime->Second = (Str[Index++] - '0') * 10;
+ EfiTime->Second += (Str[Index++] - '0');
+ if (EfiTime->Second > 59) {
+ return FALSE;
+ }
+
+ /* Note: we did not adjust the time based on time zone information */
+
+ return TRUE;
+}
+
+/**
+
+ Check the validity of TimeStamp Token Information.
+
+ @param[in] TstInfo Pointer to the TS_TST_INFO structure.
+ @param[in] TimestampedData Pointer to the data to be time-stamped.
+ @param[in] DataSize Size of timestamped data in bytes.
+
+ @retval TRUE The TimeStamp Token Information is valid.
+ @retval FALSE Invalid TimeStamp Token Information.
+
+**/
+BOOLEAN
+EFIAPI
+CheckTSTInfo (
+ IN CONST TS_TST_INFO *TstInfo,
+ IN CONST UINT8 *TimestampedData,
+ IN UINTN DataSize
+ )
+{
+ BOOLEAN Status;
+ TS_MESSAGE_IMPRINT *Imprint;
+ X509_ALGOR *HashAlgo;
+ CONST EVP_MD *Md;
+ EVP_MD_CTX *MdCtx;
+ UINTN MdSize;
+ UINT8 *HashedMsg;
+
+ //
+ // Initialization
+ //
+ Status = FALSE;
+ HashAlgo = NULL;
+ HashedMsg = NULL;
+ MdCtx = NULL;
+
+ //
+ // -- Check version number of Timestamp:
+ // The version field (currently v1) describes the version of the time-stamp token.
+ // Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.
+ //
+ if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {
+ return FALSE;
+ }
+
+ //
+ // -- Check Policies
+ // The policy field MUST indicate the TSA's policy under which the response was produced.
+ //
+ if (TstInfo->Policy == NULL) {
+ /// NOTE: Need to check if the requested and returned policies.
+ /// We have no information about the Requested TSA Policy.
+ return FALSE;
+ }
+
+ //
+ // -- Compute & Check Message Imprint
+ //
+ Imprint = TstInfo->MessageImprint;
+ HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);
+
+ Md = EVP_get_digestbyobj (HashAlgo->algorithm);
+ if (Md == NULL) {
+ goto _Exit;
+ }
+
+ MdSize = EVP_MD_size (Md);
+ HashedMsg = AllocateZeroPool (MdSize);
+ if (HashedMsg == NULL) {
+ goto _Exit;
+ }
+ MdCtx = EVP_MD_CTX_new ();
+ if (MdCtx == NULL) {
+ goto _Exit;
+ }
+ if ((EVP_DigestInit_ex (MdCtx, Md, NULL) != 1) ||
+ (EVP_DigestUpdate (MdCtx, TimestampedData, DataSize) != 1) ||
+ (EVP_DigestFinal (MdCtx, HashedMsg, NULL) != 1)) {
+ goto _Exit;
+ }
+ if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
+ (CompareMem (HashedMsg, ASN1_STRING_get0_data (Imprint->HashedMessage), MdSize) != 0)) {
+ goto _Exit;
+ }
+
+ //
+ // -- Check Nonces
+ //
+ if (TstInfo->Nonce != NULL) {
+ //
+ // Nonces is optional, No error if no nonce is returned;
+ //
+ }
+
+ //
+ // -- Check if the TSA name and signer certificate is matched.
+ //
+ if (TstInfo->Tsa != NULL) {
+ //
+ // Ignored the optional Tsa field checking.
+ //
+ }
+
+ Status = TRUE;
+
+_Exit:
+ X509_ALGOR_free (HashAlgo);
+ EVP_MD_CTX_free (MdCtx);
+ if (HashedMsg != NULL) {
+ FreePool (HashedMsg);
+ }
+
+ return Status;
+}
+
+/**
+ Verifies the validity of a TimeStamp Token as described in RFC 3161 ("Internet
+ X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)").
+
+ If TSToken is NULL, then return FALSE.
+ If TimestampedData is NULL, then return FALSE.
+
+ @param[in] TSToken Pointer to the RFC3161 TimeStamp Token, which is generated
+ by a TSA and located in the software publisher's SignerInfo
+ structure.
+ @param[in] TokenSize Size of the TimeStamp Token in bytes.
+ @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER.
+ @param[in] CertSize Size of the trusted TSA certificate in bytes.
+ @param[in] TimestampedData Pointer to the data to be time-stamped.
+ @param[in] DataSize Size of timestamped data in bytes.
+ @param[out] SigningTime Return the time of timestamp generation time if the timestamp
+ signature is valid.
+
+ @retval TRUE The specified timestamp token is valid.
+ @retval FALSE Invalid timestamp token.
+
+**/
+BOOLEAN
+EFIAPI
+TimestampTokenVerify (
+ IN CONST UINT8 *TSToken,
+ IN UINTN TokenSize,
+ IN CONST UINT8 *TsaCert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *TimestampedData,
+ IN UINTN DataSize,
+ OUT EFI_TIME *SigningTime
+ )
+{
+ BOOLEAN Status;
+ CONST UINT8 *TokenTemp;
+ PKCS7 *Pkcs7;
+ X509 *Cert;
+ CONST UINT8 *CertTemp;
+ X509_STORE *CertStore;
+ BIO *OutBio;
+ UINT8 *TstData;
+ UINTN TstSize;
+ CONST UINT8 *TstTemp;
+ TS_TST_INFO *TstInfo;
+
+ Status = FALSE;
+
+ //
+ // Check input parameters
+ //
+ if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||
+ (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ //
+ // Initializations
+ //
+ if (SigningTime != NULL) {
+ SetMem (SigningTime, sizeof (EFI_TIME), 0);
+ }
+ Pkcs7 = NULL;
+ Cert = NULL;
+ CertStore = NULL;
+ OutBio = NULL;
+ TstData = NULL;
+ TstInfo = NULL;
+
+ //
+ // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.
+ //
+ TokenTemp = TSToken;
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &TokenTemp, (int) TokenSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // The timestamp signature (TSA's response) will be one PKCS#7 signed data.
+ //
+ if (!PKCS7_type_is_signed (Pkcs7)) {
+ goto _Exit;
+ }
+
+ //
+ // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.
+ //
+ CertTemp = TsaCert;
+ Cert = d2i_X509 (NULL, &CertTemp, (long) CertSize);
+ if (Cert == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Setup X509 Store for trusted certificate.
+ //
+ CertStore = X509_STORE_new ();
+ if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {
+ goto _Exit;
+ }
+
+ //
+ // Allow partial certificate chains, terminated by a non-self-signed but
+ // still trusted intermediate certificate. Also disable time checks.
+ //
+ X509_STORE_set_flags (CertStore,
+ X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
+
+ X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
+
+ //
+ // Verifies the PKCS#7 signedData structure, and output the signed contents.
+ //
+ OutBio = BIO_new (BIO_s_mem ());
+ if (OutBio == NULL) {
+ goto _Exit;
+ }
+ if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {
+ goto _Exit;
+ }
+
+ //
+ // Read the signed contents detached in timestamp signature.
+ //
+ TstData = AllocateZeroPool (2048);
+ if (TstData == NULL) {
+ goto _Exit;
+ }
+ TstSize = BIO_read (OutBio, (void *) TstData, 2048);
+
+ //
+ // Construct TS_TST_INFO structure from the signed contents.
+ //
+ TstTemp = TstData;
+ TstInfo = d2i_TS_TST_INFO (NULL, (const unsigned char **) &TstTemp,
+ (int)TstSize);
+ if (TstInfo == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Check TS_TST_INFO structure.
+ //
+ Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);
+ if (!Status) {
+ goto _Exit;
+ }
+
+ //
+ // Retrieve the signing time from TS_TST_INFO structure.
+ //
+ if (SigningTime != NULL) {
+ SetMem (SigningTime, sizeof (EFI_TIME), 0);
+ Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);
+ }
+
+_Exit:
+ //
+ // Release Resources
+ //
+ PKCS7_free (Pkcs7);
+ X509_free (Cert);
+ X509_STORE_free (CertStore);
+ BIO_free (OutBio);
+ TS_TST_INFO_free (TstInfo);
+
+ if (TstData != NULL) {
+ FreePool (TstData);
+ }
+
+ return Status;
+}
+
+/**
+ Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode
+ signature.
+
+ If AuthData is NULL, then return FALSE.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed
+ PE/COFF image to be verified.
+ @param[in] DataSize Size of the Authenticode Signature in bytes.
+ @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which
+ is used for TSA certificate chain verification.
+ @param[in] CertSize Size of the trusted certificate in bytes.
+ @param[out] SigningTime Return the time of timestamp generation time if the timestamp
+ signature is valid.
+
+ @retval TRUE The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature.
+ @retval FALSE No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data.
+
+**/
+BOOLEAN
+EFIAPI
+ImageTimestampVerify (
+ IN CONST UINT8 *AuthData,
+ IN UINTN DataSize,
+ IN CONST UINT8 *TsaCert,
+ IN UINTN CertSize,
+ OUT EFI_TIME *SigningTime
+ )
+{
+ BOOLEAN Status;
+ PKCS7 *Pkcs7;
+ CONST UINT8 *Temp;
+ STACK_OF(PKCS7_SIGNER_INFO) *SignerInfos;
+ PKCS7_SIGNER_INFO *SignInfo;
+ UINTN Index;
+ STACK_OF(X509_ATTRIBUTE) *Sk;
+ X509_ATTRIBUTE *Xa;
+ ASN1_OBJECT *XaObj;
+ ASN1_TYPE *Asn1Type;
+ ASN1_OCTET_STRING *EncDigest;
+ UINT8 *TSToken;
+ UINTN TokenSize;
+
+ //
+ // Input Parameters Checking.
+ //
+ if ((AuthData == NULL) || (TsaCert == NULL)) {
+ return FALSE;
+ }
+
+ if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ //
+ // Register & Initialize necessary digest algorithms for PKCS#7 Handling.
+ //
+ if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||
+ (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0) {
+ return FALSE;
+ }
+
+ //
+ // Initialization.
+ //
+ Status = FALSE;
+ Pkcs7 = NULL;
+ SignInfo = NULL;
+
+ //
+ // Decode ASN.1-encoded Authenticode data into PKCS7 structure.
+ //
+ Temp = AuthData;
+ Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) DataSize);
+ if (Pkcs7 == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Check if there is one and only one signer.
+ //
+ SignerInfos = PKCS7_get_signer_info (Pkcs7);
+ if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {
+ goto _Exit;
+ }
+
+ //
+ // Locate the TimeStamp CounterSignature.
+ //
+ SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);
+ if (SignInfo == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // Locate Message Digest which will be the data to be time-stamped.
+ //
+ EncDigest = SignInfo->enc_digest;
+ if (EncDigest == NULL) {
+ goto _Exit;
+ }
+
+ //
+ // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field
+ // of SignerInfo.
+ //
+ Sk = SignInfo->unauth_attr;
+ if (Sk == NULL) { // No timestamp counterSignature.
+ goto _Exit;
+ }
+
+ Asn1Type = NULL;
+ for (Index = 0; Index < (UINTN) sk_X509_ATTRIBUTE_num (Sk); Index++) {
+ //
+ // Search valid RFC3161 timestamp counterSignature based on OBJID.
+ //
+ Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);
+ if (Xa == NULL) {
+ continue;
+ }
+ XaObj = X509_ATTRIBUTE_get0_object(Xa);
+ if (XaObj == NULL) {
+ continue;
+ }
+ if ((OBJ_length(XaObj) != sizeof (mSpcRFC3161OidValue)) ||
+ (CompareMem (OBJ_get0_data(XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0)) {
+ continue;
+ }
+ Asn1Type = X509_ATTRIBUTE_get0_type(Xa, 0);
+ }
+
+ if (Asn1Type == NULL) {
+ Status = FALSE;
+ goto _Exit;
+ }
+ TSToken = Asn1Type->value.octet_string->data;
+ TokenSize = Asn1Type->value.octet_string->length;
+
+ //
+ // TimeStamp counterSignature (Token) verification.
+ //
+ Status = TimestampTokenVerify (
+ TSToken,
+ TokenSize,
+ TsaCert,
+ CertSize,
+ EncDigest->data,
+ EncDigest->length,
+ SigningTime
+ );
+
+_Exit:
+ //
+ // Release Resources
+ //
+ PKCS7_free (Pkcs7);
+
+ return Status;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c new file mode 100644 index 000000000..907988814 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c @@ -0,0 +1,42 @@ +/** @file
+ RFC3161 Timestamp Countersignature Verification Wrapper Implementation which does
+ not provide real capabilities.
+
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode
+ signature.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed
+ PE/COFF image to be verified.
+ @param[in] DataSize Size of the Authenticode Signature in bytes.
+ @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which
+ is used for TSA certificate chain verification.
+ @param[in] CertSize Size of the trusted certificate in bytes.
+ @param[out] SigningTime Return the time of timestamp generation time if the timestamp
+ signature is valid.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+ImageTimestampVerify (
+ IN CONST UINT8 *AuthData,
+ IN UINTN DataSize,
+ IN CONST UINT8 *TsaCert,
+ IN UINTN CertSize,
+ OUT EFI_TIME *SigningTime
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c new file mode 100644 index 000000000..b1393a89c --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c @@ -0,0 +1,832 @@ +/** @file
+ X.509 Certificate Handler Wrapper Implementation over OpenSSL.
+
+Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/x509.h>
+#include <openssl/rsa.h>
+
+/**
+ Construct a X509 object from DER-encoded certificate data.
+
+ If Cert is NULL, then return FALSE.
+ If SingleX509Cert is NULL, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded certificate data.
+ @param[in] CertSize The size of certificate data in bytes.
+ @param[out] SingleX509Cert The generated X509 object.
+
+ @retval TRUE The X509 object generation succeeded.
+ @retval FALSE The operation failed.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificate (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **SingleX509Cert
+ )
+{
+ X509 *X509Cert;
+ CONST UINT8 *Temp;
+
+ //
+ // Check input parameters.
+ //
+ if (Cert == NULL || SingleX509Cert == NULL || CertSize > INT_MAX) {
+ return FALSE;
+ }
+
+ //
+ // Read DER-encoded X509 Certificate and Construct X509 object.
+ //
+ Temp = Cert;
+ X509Cert = d2i_X509 (NULL, &Temp, (long) CertSize);
+ if (X509Cert == NULL) {
+ return FALSE;
+ }
+
+ *SingleX509Cert = (UINT8 *) X509Cert;
+
+ return TRUE;
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ If X509Stack is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param[in] Args VA_LIST marker for the variable argument list.
+ A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval TRUE The X509 stack construction succeeded.
+ @retval FALSE The construction operation failed.
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStackV (
+ IN OUT UINT8 **X509Stack,
+ IN VA_LIST Args
+ )
+{
+ UINT8 *Cert;
+ UINTN CertSize;
+ X509 *X509Cert;
+ STACK_OF(X509) *CertStack;
+ BOOLEAN Status;
+ UINTN Index;
+
+ //
+ // Check input parameters.
+ //
+ if (X509Stack == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ //
+ // Initialize X509 stack object.
+ //
+ CertStack = (STACK_OF(X509) *) (*X509Stack);
+ if (CertStack == NULL) {
+ CertStack = sk_X509_new_null ();
+ if (CertStack == NULL) {
+ return Status;
+ }
+ }
+
+ for (Index = 0; ; Index++) {
+ //
+ // If Cert is NULL, then it is the end of the list.
+ //
+ Cert = VA_ARG (Args, UINT8 *);
+ if (Cert == NULL) {
+ break;
+ }
+
+ CertSize = VA_ARG (Args, UINTN);
+ if (CertSize == 0) {
+ break;
+ }
+
+ //
+ // Construct X509 Object from the given DER-encoded certificate data.
+ //
+ X509Cert = NULL;
+ Status = X509ConstructCertificate (
+ (CONST UINT8 *) Cert,
+ CertSize,
+ (UINT8 **) &X509Cert
+ );
+ if (!Status) {
+ if (X509Cert != NULL) {
+ X509_free (X509Cert);
+ }
+ break;
+ }
+
+ //
+ // Insert the new X509 object into X509 stack object.
+ //
+ sk_X509_push (CertStack, X509Cert);
+ }
+
+ if (!Status) {
+ sk_X509_pop_free (CertStack, X509_free);
+ } else {
+ *X509Stack = (UINT8 *) CertStack;
+ }
+
+ return Status;
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ If X509Stack is NULL, then return FALSE.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param ... A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval TRUE The X509 stack construction succeeded.
+ @retval FALSE The construction operation failed.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStack (
+ IN OUT UINT8 **X509Stack,
+ ...
+ )
+{
+ VA_LIST Args;
+ BOOLEAN Result;
+
+ VA_START (Args, X509Stack);
+ Result = X509ConstructCertificateStackV (X509Stack, Args);
+ VA_END (Args);
+ return Result;
+}
+
+/**
+ Release the specified X509 object.
+
+ If X509Cert is NULL, then return FALSE.
+
+ @param[in] X509Cert Pointer to the X509 object to be released.
+
+**/
+VOID
+EFIAPI
+X509Free (
+ IN VOID *X509Cert
+ )
+{
+ //
+ // Check input parameters.
+ //
+ if (X509Cert == NULL) {
+ return;
+ }
+
+ //
+ // Free OpenSSL X509 object.
+ //
+ X509_free ((X509 *) X509Cert);
+}
+
+/**
+ Release the specified X509 stack object.
+
+ If X509Stack is NULL, then return FALSE.
+
+ @param[in] X509Stack Pointer to the X509 stack object to be released.
+
+**/
+VOID
+EFIAPI
+X509StackFree (
+ IN VOID *X509Stack
+ )
+{
+ //
+ // Check input parameters.
+ //
+ if (X509Stack == NULL) {
+ return;
+ }
+
+ //
+ // Free OpenSSL X509 stack object.
+ //
+ sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free);
+}
+
+/**
+ Retrieve the subject bytes from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CertSubject Pointer to the retrieved certificate subject bytes.
+ @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input,
+ and the size of buffer returned CertSubject on output.
+
+ If Cert is NULL, then return FALSE.
+ If SubjectSize is NULL, then return FALSE.
+
+ @retval TRUE The certificate subject retrieved successfully.
+ @retval FALSE Invalid certificate, or the SubjectSize is too small for the result.
+ The SubjectSize will be updated with the required size.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetSubjectName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *CertSubject,
+ IN OUT UINTN *SubjectSize
+ )
+{
+ BOOLEAN Status;
+ X509 *X509Cert;
+ X509_NAME *X509Name;
+ UINTN X509NameSize;
+
+ //
+ // Check input parameters.
+ //
+ if (Cert == NULL || SubjectSize == NULL) {
+ return FALSE;
+ }
+
+ X509Cert = NULL;
+
+ //
+ // Read DER-encoded X509 Certificate and Construct X509 object.
+ //
+ Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
+ if ((X509Cert == NULL) || (!Status)) {
+ Status = FALSE;
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ //
+ // Retrieve subject name from certificate object.
+ //
+ X509Name = X509_get_subject_name (X509Cert);
+ if (X509Name == NULL) {
+ goto _Exit;
+ }
+
+ X509NameSize = i2d_X509_NAME(X509Name, NULL);
+ if (*SubjectSize < X509NameSize) {
+ *SubjectSize = X509NameSize;
+ goto _Exit;
+ }
+ *SubjectSize = X509NameSize;
+ if (CertSubject != NULL) {
+ i2d_X509_NAME(X509Name, &CertSubject);
+ Status = TRUE;
+ }
+
+_Exit:
+ //
+ // Release Resources.
+ //
+ if (X509Cert != NULL) {
+ X509_free (X509Cert);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieve a string from one X.509 certificate base on the Request_NID.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] Request_NID NID of string to obtain
+ @param[out] CommonName Buffer to contain the retrieved certificate common
+ name string (UTF8). At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no NID Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+STATIC
+RETURN_STATUS
+InternalX509GetNIDName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN INT32 Request_NID,
+ OUT CHAR8 *CommonName, OPTIONAL
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ RETURN_STATUS ReturnStatus;
+ BOOLEAN Status;
+ X509 *X509Cert;
+ X509_NAME *X509Name;
+ INT32 Index;
+ INTN Length;
+ X509_NAME_ENTRY *Entry;
+ ASN1_STRING *EntryData;
+ UINT8 *UTF8Name;
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ UTF8Name = NULL;
+
+ //
+ // Check input parameters.
+ //
+ if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {
+ return ReturnStatus;
+ }
+ if ((CommonName != NULL) && (*CommonNameSize == 0)) {
+ return ReturnStatus;
+ }
+
+ X509Cert = NULL;
+ //
+ // Read DER-encoded X509 Certificate and Construct X509 object.
+ //
+ Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
+ if ((X509Cert == NULL) || (!Status)) {
+ //
+ // Invalid X.509 Certificate
+ //
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ //
+ // Retrieve subject name from certificate object.
+ //
+ X509Name = X509_get_subject_name (X509Cert);
+ if (X509Name == NULL) {
+ //
+ // Fail to retrieve subject name content
+ //
+ goto _Exit;
+ }
+
+ //
+ // Retrive the string from X.509 Subject base on the Request_NID
+ //
+ Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);
+ if (Index < 0) {
+ //
+ // No Request_NID name entry exists in X509_NAME object
+ //
+ *CommonNameSize = 0;
+ ReturnStatus = RETURN_NOT_FOUND;
+ goto _Exit;
+ }
+
+ Entry = X509_NAME_get_entry (X509Name, Index);
+ if (Entry == NULL) {
+ //
+ // Fail to retrieve name entry data
+ //
+ *CommonNameSize = 0;
+ ReturnStatus = RETURN_NOT_FOUND;
+ goto _Exit;
+ }
+
+ EntryData = X509_NAME_ENTRY_get_data (Entry);
+
+ Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);
+ if (Length < 0) {
+ //
+ // Fail to convert the Name string
+ //
+ *CommonNameSize = 0;
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ goto _Exit;
+ }
+
+ if (CommonName == NULL) {
+ *CommonNameSize = Length + 1;
+ ReturnStatus = RETURN_BUFFER_TOO_SMALL;
+ } else {
+ *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;
+ CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);
+ CommonName[*CommonNameSize - 1] = '\0';
+ ReturnStatus = RETURN_SUCCESS;
+ }
+
+_Exit:
+ //
+ // Release Resources.
+ //
+ if (X509Cert != NULL) {
+ X509_free (X509Cert);
+ }
+ if (UTF8Name != NULL) {
+ OPENSSL_free (UTF8Name);
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the common name (CN) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CommonName Buffer to contain the retrieved certificate common
+ name string. At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no CommonName entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetCommonName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *CommonName, OPTIONAL
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize);
+}
+
+/**
+ Retrieve the organization name (O) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] NameBuffer Buffer to contain the retrieved certificate organization
+ name string. At most NameBufferSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,
+ and the size of buffer returned Name on output.
+ If NameBuffer is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate Organization Name retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If NameBufferSize is NULL.
+ If NameBuffer is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no Organization Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetOrganizationName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *NameBuffer, OPTIONAL
+ IN OUT UINTN *NameBufferSize
+ )
+{
+ return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);
+}
+
+/**
+ Retrieve the RSA Public Key from one DER-encoded X509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved
+ RSA public key component. Use RsaFree() function to free the
+ resource.
+
+ If Cert is NULL, then return FALSE.
+ If RsaContext is NULL, then return FALSE.
+
+ @retval TRUE RSA Public Key was retrieved successfully.
+ @retval FALSE Fail to retrieve RSA public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGetPublicKeyFromX509 (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT VOID **RsaContext
+ )
+{
+ BOOLEAN Status;
+ EVP_PKEY *Pkey;
+ X509 *X509Cert;
+
+ //
+ // Check input parameters.
+ //
+ if (Cert == NULL || RsaContext == NULL) {
+ return FALSE;
+ }
+
+ Pkey = NULL;
+ X509Cert = NULL;
+
+ //
+ // Read DER-encoded X509 Certificate and Construct X509 object.
+ //
+ Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
+ if ((X509Cert == NULL) || (!Status)) {
+ Status = FALSE;
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ //
+ // Retrieve and check EVP_PKEY data from X509 Certificate.
+ //
+ Pkey = X509_get_pubkey (X509Cert);
+ if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {
+ goto _Exit;
+ }
+
+ //
+ // Duplicate RSA Context from the retrieved EVP_PKEY.
+ //
+ if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {
+ Status = TRUE;
+ }
+
+_Exit:
+ //
+ // Release Resources.
+ //
+ if (X509Cert != NULL) {
+ X509_free (X509Cert);
+ }
+
+ if (Pkey != NULL) {
+ EVP_PKEY_free (Pkey);
+ }
+
+ return Status;
+}
+
+/**
+ Verify one X509 certificate was issued by the trusted CA.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] CACert Pointer to the DER-encoded trusted CA certificate.
+ @param[in] CACertSize Size of the CA Certificate in bytes.
+
+ If Cert is NULL, then return FALSE.
+ If CACert is NULL, then return FALSE.
+
+ @retval TRUE The certificate was issued by the trusted CA.
+ @retval FALSE Invalid certificate or the certificate was not issued by the given
+ trusted CA.
+
+**/
+BOOLEAN
+EFIAPI
+X509VerifyCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *CACert,
+ IN UINTN CACertSize
+ )
+{
+ BOOLEAN Status;
+ X509 *X509Cert;
+ X509 *X509CACert;
+ X509_STORE *CertStore;
+ X509_STORE_CTX *CertCtx;
+
+ //
+ // Check input parameters.
+ //
+ if (Cert == NULL || CACert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ X509Cert = NULL;
+ X509CACert = NULL;
+ CertStore = NULL;
+ CertCtx = NULL;
+
+ //
+ // Register & Initialize necessary digest algorithms for certificate verification.
+ //
+ if (EVP_add_digest (EVP_md5 ()) == 0) {
+ goto _Exit;
+ }
+ if (EVP_add_digest (EVP_sha1 ()) == 0) {
+ goto _Exit;
+ }
+ if (EVP_add_digest (EVP_sha256 ()) == 0) {
+ goto _Exit;
+ }
+
+ //
+ // Read DER-encoded certificate to be verified and Construct X509 object.
+ //
+ Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
+ if ((X509Cert == NULL) || (!Status)) {
+ Status = FALSE;
+ goto _Exit;
+ }
+
+ //
+ // Read DER-encoded root certificate and Construct X509 object.
+ //
+ Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert);
+ if ((X509CACert == NULL) || (!Status)) {
+ Status = FALSE;
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ //
+ // Set up X509 Store for trusted certificate.
+ //
+ CertStore = X509_STORE_new ();
+ if (CertStore == NULL) {
+ goto _Exit;
+ }
+ if (!(X509_STORE_add_cert (CertStore, X509CACert))) {
+ goto _Exit;
+ }
+
+ //
+ // Allow partial certificate chains, terminated by a non-self-signed but
+ // still trusted intermediate certificate. Also disable time checks.
+ //
+ X509_STORE_set_flags (CertStore,
+ X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
+
+ //
+ // Set up X509_STORE_CTX for the subsequent verification operation.
+ //
+ CertCtx = X509_STORE_CTX_new ();
+ if (CertCtx == NULL) {
+ goto _Exit;
+ }
+ if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {
+ goto _Exit;
+ }
+
+ //
+ // X509 Certificate Verification.
+ //
+ Status = (BOOLEAN) X509_verify_cert (CertCtx);
+ X509_STORE_CTX_cleanup (CertCtx);
+
+_Exit:
+ //
+ // Release Resources.
+ //
+ if (X509Cert != NULL) {
+ X509_free (X509Cert);
+ }
+
+ if (X509CACert != NULL) {
+ X509_free (X509CACert);
+ }
+
+ if (CertStore != NULL) {
+ X509_STORE_free (CertStore);
+ }
+
+ X509_STORE_CTX_free (CertCtx);
+
+ return Status;
+}
+
+/**
+ Retrieve the TBSCertificate from one given X.509 certificate.
+
+ @param[in] Cert Pointer to the given DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] TBSCert DER-Encoded To-Be-Signed certificate.
+ @param[out] TBSCertSize Size of the TBS certificate in bytes.
+
+ If Cert is NULL, then return FALSE.
+ If TBSCert is NULL, then return FALSE.
+ If TBSCertSize is NULL, then return FALSE.
+
+ @retval TRUE The TBSCertificate was retrieved successfully.
+ @retval FALSE Invalid X.509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetTBSCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **TBSCert,
+ OUT UINTN *TBSCertSize
+ )
+{
+ CONST UINT8 *Temp;
+ UINT32 Asn1Tag;
+ UINT32 ObjClass;
+ UINTN Length;
+
+ //
+ // Check input parameters.
+ //
+ if ((Cert == NULL) || (TBSCert == NULL) ||
+ (TBSCertSize == NULL) || (CertSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ //
+ // An X.509 Certificate is: (defined in RFC3280)
+ // Certificate ::= SEQUENCE {
+ // tbsCertificate TBSCertificate,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING }
+ //
+ // and
+ //
+ // TBSCertificate ::= SEQUENCE {
+ // version [0] Version DEFAULT v1,
+ // ...
+ // }
+ //
+ // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
+ // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
+ //
+ Temp = Cert;
+ Length = 0;
+ ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);
+
+ if (Asn1Tag != V_ASN1_SEQUENCE) {
+ return FALSE;
+ }
+
+ *TBSCert = (UINT8 *)Temp;
+
+ ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);
+ //
+ // Verify the parsed TBSCertificate is one correct SEQUENCE data.
+ //
+ if (Asn1Tag != V_ASN1_SEQUENCE) {
+ return FALSE;
+ }
+
+ *TBSCertSize = Length + (Temp - *TBSCert);
+
+ return TRUE;
+}
diff --git a/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c new file mode 100644 index 000000000..14309825e --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c @@ -0,0 +1,294 @@ +/** @file
+ X.509 Certificate Handler Wrapper Implementation which does not provide
+ real capabilities.
+
+Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+
+/**
+ Construct a X509 object from DER-encoded certificate data.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded certificate data.
+ @param[in] CertSize The size of certificate data in bytes.
+ @param[out] SingleX509Cert The generated X509 object.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificate (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **SingleX509Cert
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ If X509Stack is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param[in] Args VA_LIST marker for the variable argument list.
+ A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval TRUE The X509 stack construction succeeded.
+ @retval FALSE The construction operation failed.
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStackV (
+ IN OUT UINT8 **X509Stack,
+ IN VA_LIST Args
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param ... A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStack (
+ IN OUT UINT8 **X509Stack,
+ ...
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Release the specified X509 object.
+
+ If the interface is not supported, then ASSERT().
+
+ @param[in] X509Cert Pointer to the X509 object to be released.
+
+**/
+VOID
+EFIAPI
+X509Free (
+ IN VOID *X509Cert
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Release the specified X509 stack object.
+
+ If the interface is not supported, then ASSERT().
+
+ @param[in] X509Stack Pointer to the X509 stack object to be released.
+
+**/
+VOID
+EFIAPI
+X509StackFree (
+ IN VOID *X509Stack
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Retrieve the subject bytes from one X.509 certificate.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CertSubject Pointer to the retrieved certificate subject bytes.
+ @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input,
+ and the size of buffer returned CertSubject on output.
+
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetSubjectName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *CertSubject,
+ IN OUT UINTN *SubjectSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Retrieve the common name (CN) string from one X.509 certificate.
+
+ Return RETURN_UNSUPPORTED to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CommonName Buffer to contain the retrieved certificate common
+ name string (UTF8). At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetCommonName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *CommonName, OPTIONAL
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ ASSERT (FALSE);
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Retrieve the organization name (ON) string from one X.509 certificate.
+
+ Return RETURN_UNSUPPORTED to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] NameBuffer Buffer to contain the retrieved certificate organization
+ name string. At most NameBufferSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,
+ and the size of buffer returned Name on output.
+ If NameBuffer is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetOrganizationName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *NameBuffer, OPTIONAL
+ IN OUT UINTN *NameBufferSize
+ )
+{
+ ASSERT (FALSE);
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Retrieve the RSA Public Key from one DER-encoded X509 certificate.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved
+ RSA public key component. Use RsaFree() function to free the
+ resource.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGetPublicKeyFromX509 (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT VOID **RsaContext
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Verify one X509 certificate was issued by the trusted CA.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] CACert Pointer to the DER-encoded trusted CA certificate.
+ @param[in] CACertSize Size of the CA Certificate in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509VerifyCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *CACert,
+ IN UINTN CACertSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Retrieve the TBSCertificate from one given X.509 certificate.
+
+ Return FALSE to indicate this interface is not supported.
+
+ @param[in] Cert Pointer to the given DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] TBSCert DER-Encoded To-Be-Signed certificate.
+ @param[out] TBSCertSize Size of the TBS certificate in bytes.
+
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetTBSCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **TBSCert,
+ OUT UINTN *TBSCertSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
|