1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			1022 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1022 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Common interfaces to call Security library.
 | |
| 
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "IpSecCryptIo.h"
 | |
| //
 | |
| // The informations for the supported Encrypt/Decrpt Alogrithm.
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {
 | |
|   {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},
 | |
|   {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},
 | |
|   {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},
 | |
|   {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}
 | |
| };
 | |
| 
 | |
| //
 | |
| // The informations for the supported Authentication algorithm
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {
 | |
|   {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
 | |
|   {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
 | |
|   {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}
 | |
| };
 | |
| 
 | |
| //
 | |
| // The information for the supported Hash aglorithm
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {
 | |
|   {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
 | |
|   {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
 | |
|   {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}
 | |
| };
 | |
| 
 | |
| BOOLEAN  mInitialRandomSeed = FALSE;
 | |
| 
 | |
| /**
 | |
|   Get the block size of specified encryption algorithm.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The encryption algorithm ID.
 | |
| 
 | |
|   @return The value of block size.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetEncryptBlockSize (
 | |
|   IN UINT8   AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
 | |
|       return mIpsecEncryptAlgorithmList[Index].BlockSize;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the key length of the specified encryption algorithm.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The encryption algorithm ID.
 | |
| 
 | |
|   @return The value of key length.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetEncryptKeyLength (
 | |
|   IN UINT8   AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
 | |
|       return mIpsecEncryptAlgorithmList[Index].KeyLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the IV size of the specified encryption algorithm.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The encryption algorithm ID.
 | |
| 
 | |
|   @return The value of IV size.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetEncryptIvLength (
 | |
|   IN UINT8 AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
 | |
|       return mIpsecEncryptAlgorithmList[Index].IvLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the HMAC digest length by the specified Algorithm ID.
 | |
| 
 | |
|   @param[in]  AlgorithmId  The specified Alogrithm ID.
 | |
| 
 | |
|   @return The digest length of the specified Authentication Algorithm ID.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetHmacDigestLength (
 | |
|   IN UINT8  AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {
 | |
|       //
 | |
|       // Return the Digest Length of the Algorithm.
 | |
|       //
 | |
|       return mIpsecAuthAlgorithmList[Index].DigestLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the ICV size of the specified Authenticaion algorithm.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The Authentication algorithm ID.
 | |
| 
 | |
|   @return The value of ICV size.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetIcvLength (
 | |
|   IN UINT8  AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
 | |
|       return mIpsecAuthAlgorithmList[Index].IcvLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate a random data for IV. If the IvSize is zero, not needed to create
 | |
|   IV and return EFI_SUCCESS.
 | |
| 
 | |
|   @param[in]  IvBuffer  The pointer of the IV buffer.
 | |
|   @param[in]  IvSize    The IV size in bytes.
 | |
| 
 | |
|   @retval     EFI_SUCCESS  Create a random data for IV.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecGenerateIv (
 | |
|   IN UINT8                           *IvBuffer,
 | |
|   IN UINTN                           IvSize
 | |
|   )
 | |
| {
 | |
|   if (IvSize != 0) {
 | |
|     return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get index of the specified encryption algorithm from the mIpsecEncryptAlgorithmList.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The encryption algorithm ID.
 | |
| 
 | |
|   @return the index.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetIndexFromEncList (
 | |
|   IN UINT8   AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
 | |
|       return Index;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get index of the specified encryption algorithm from the mIpsecAuthAlgorithmList.
 | |
| 
 | |
|   @param[in]  AlgorithmId          The encryption algorithm ID.
 | |
| 
 | |
|   @return the index.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| IpSecGetIndexFromAuthList (
 | |
|   IN UINT8   AlgorithmId
 | |
|   )
 | |
| {
 | |
|   UINT8 Index;
 | |
| 
 | |
|   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
 | |
|     if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
 | |
|       //
 | |
|       // The BlockSize is same with IvSize.
 | |
|       //
 | |
|       return Index;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Encrypt the buffer.
 | |
| 
 | |
|   This function calls relevant encryption interface from CryptoLib according to
 | |
|   the input algorithm ID. The InData should be multiple of block size. This function
 | |
|   doesn't perform the padding. If it has the Ivec data, the length of it should be
 | |
|   same with the block size. The block size is different from the different algorithm.
 | |
| 
 | |
|   @param[in]       AlgorithmId    The Algorithm identification defined in RFC.
 | |
|   @param[in]       Key            Pointer to the buffer containing encrypting key.
 | |
|   @param[in]       KeyBits        The length of the key in bits.
 | |
|   @param[in]       Ivec           Point to the buffer containing the Initialization
 | |
|                                   Vector (IV) data.
 | |
|   @param[in]       InData         Point to the buffer containing the data to be
 | |
|                                   encrypted.
 | |
|   @param[in]       InDataLength   The length of InData in Bytes.
 | |
|   @param[out]      OutData        Point to the buffer that receives the encryption
 | |
|                                   output.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED       The input Algorithm is not supported.
 | |
|   @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.
 | |
|   @retval EFI_SUCCESS           The operation completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoEncrypt (
 | |
|   IN CONST UINT8      AlgorithmId,
 | |
|   IN CONST UINT8      *Key,
 | |
|   IN CONST UINTN      KeyBits,
 | |
|   IN CONST UINT8      *Ivec, OPTIONAL
 | |
|   IN       UINT8      *InData,
 | |
|   IN       UINTN      InDataLength,
 | |
|      OUT   UINT8      *OutData
 | |
|   )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   UINTN         ContextSize;
 | |
|   UINT8         *Context;
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   Status = EFI_UNSUPPORTED;
 | |
| 
 | |
|   switch (AlgorithmId) {
 | |
| 
 | |
|   case IKE_EALG_NULL:
 | |
|   case IKE_EALG_NONE:
 | |
|     CopyMem (OutData, InData, InDataLength);
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   case IKE_EALG_3DESCBC:
 | |
|   case IKE_EALG_AESCBC:
 | |
|     Index = IpSecGetIndexFromEncList (AlgorithmId);
 | |
|     if (Index == -1) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Get Context Size
 | |
|     //
 | |
|     ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();
 | |
|     Context     = AllocateZeroPool (ContextSize);
 | |
| 
 | |
|     if (Context == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Initiate Context
 | |
|     //
 | |
|     if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
 | |
|       if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {
 | |
|         Status = EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return Status;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   if (Context != NULL) {
 | |
|     FreePool (Context);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Decrypts the buffer.
 | |
| 
 | |
|   This function calls relevant Decryption interface from CryptoLib according to
 | |
|   the input algorithm ID. The InData should be multiple of block size. This function
 | |
|   doesn't perform the padding. If it has the Ivec data, the length of it should be
 | |
|   same with the block size. The block size is different from the different algorithm.
 | |
| 
 | |
|   @param[in]       AlgorithmId    The Algorithm identification defined in RFC.
 | |
|   @param[in]       Key            Pointer to the buffer containing encrypting key.
 | |
|   @param[in]       KeyBits        The length of the key in bits.
 | |
|   @param[in]       Ivec           Point to the buffer containing the Initialization
 | |
|                                   Vector (IV) data.
 | |
|   @param[in]       InData         Point to the buffer containing the data to be
 | |
|                                   decrypted.
 | |
|   @param[in]       InDataLength   The length of InData in Bytes.
 | |
|   @param[out]      OutData        Pointer to the buffer that receives the decryption
 | |
|                                   output.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED       The input Algorithm is not supported.
 | |
|   @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.
 | |
|   @retval EFI_SUCCESS           The operation completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoDecrypt (
 | |
|   IN CONST UINT8      AlgorithmId,
 | |
|   IN CONST UINT8      *Key,
 | |
|   IN CONST UINTN      KeyBits,
 | |
|   IN CONST UINT8      *Ivec, OPTIONAL
 | |
|   IN       UINT8      *InData,
 | |
|   IN       UINTN      InDataLength,
 | |
|      OUT   UINT8      *OutData
 | |
|   )
 | |
| {
 | |
|   UINTN         Index;
 | |
|   UINTN         ContextSize;
 | |
|   UINT8         *Context;
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   Status = EFI_UNSUPPORTED;
 | |
| 
 | |
|   switch (AlgorithmId) {
 | |
| 
 | |
|   case IKE_EALG_NULL:
 | |
|   case IKE_EALG_NONE:
 | |
|     CopyMem (OutData, InData, InDataLength);
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   case IKE_EALG_3DESCBC:
 | |
|   case IKE_EALG_AESCBC:
 | |
|     Index = IpSecGetIndexFromEncList(AlgorithmId);
 | |
|     if (Index == -1) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get Context Size
 | |
|     //
 | |
|     ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();
 | |
|     Context     = AllocateZeroPool (ContextSize);
 | |
|     if (Context == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Initiate Context
 | |
|     //
 | |
|     if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
 | |
|       if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {
 | |
|         Status = EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Context != NULL) {
 | |
|     FreePool (Context);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Digests the Payload with key and store the result into the OutData.
 | |
| 
 | |
|   This function calls relevant Hmac interface from CryptoLib according to
 | |
|   the input algorithm ID. It computes all datas from InDataFragment and output
 | |
|   the result into the OutData buffer. If the OutDataSize is larger than the related
 | |
|   HMAC algorithm output size, return EFI_INVALID_PARAMETER.
 | |
| 
 | |
|   @param[in]      AlgorithmId     The authentication Identification.
 | |
|   @param[in]      Key             Pointer of the authentication key.
 | |
|   @param[in]      KeyLength       The length of the Key in bytes.
 | |
|   @param[in]      InDataFragment  The list contains all data to be authenticated.
 | |
|   @param[in]      FragmentCount   The size of the InDataFragment.
 | |
|   @param[out]     OutData         For in, the buffer to receive the output data.
 | |
|                                   For out, the buffer contains the authenticated data.
 | |
|   @param[in]      OutDataSize     The size of the buffer of OutData.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.
 | |
|   @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.
 | |
|   @retval EFI_SUCCESS           Authenticate the payload successfully.
 | |
|   @retval otherwise             Authentication of the payload fails.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoHmac (
 | |
|   IN     CONST UINT8              AlgorithmId,
 | |
|   IN     CONST UINT8              *Key,
 | |
|   IN           UINTN              KeyLength,
 | |
|   IN           HASH_DATA_FRAGMENT *InDataFragment,
 | |
|   IN           UINTN              FragmentCount,
 | |
|      OUT       UINT8              *OutData,
 | |
|   IN           UINTN              OutDataSize
 | |
|   )
 | |
| {
 | |
|   UINTN        ContextSize;
 | |
|   UINTN        Index;
 | |
|   UINT8        FragmentIndex;
 | |
|   UINT8        *HashContext;
 | |
|   EFI_STATUS   Status;
 | |
|   UINT8        *OutHashData;
 | |
|   UINTN        OutHashSize;
 | |
| 
 | |
|   Status      = EFI_UNSUPPORTED;
 | |
|   OutHashData = NULL;
 | |
| 
 | |
|   OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
 | |
|   //
 | |
|   // If the expected hash data size is larger than the related Hash algorithm
 | |
|   // output length, return EFI_INVALID_PARAMETER.
 | |
|   //
 | |
|   if (OutDataSize > OutHashSize) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   OutHashData = AllocatePool (OutHashSize);
 | |
| 
 | |
|   if (OutHashData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   switch (AlgorithmId) {
 | |
| 
 | |
|   case IKE_AALG_NONE :
 | |
|   case IKE_AALG_NULL :
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   case IKE_AALG_SHA1HMAC:
 | |
|     Index = IpSecGetIndexFromAuthList (AlgorithmId);
 | |
|     if (Index == -1) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get Context Size
 | |
|     //
 | |
|     ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();
 | |
|     HashContext = AllocateZeroPool (ContextSize);
 | |
| 
 | |
|     if (HashContext == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Initiate HMAC context and hash the input data.
 | |
|     //
 | |
|     if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {
 | |
|       for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
 | |
|         if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (
 | |
|                 HashContext,
 | |
|                 InDataFragment[FragmentIndex].Data,
 | |
|                 InDataFragment[FragmentIndex].DataSize
 | |
|                 )
 | |
|           ) {
 | |
|           goto Exit;
 | |
|         }
 | |
|       }
 | |
|       if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {
 | |
|         //
 | |
|         // In some cases, like the Icv computing, the Icv size might be less than
 | |
|         // the key length size, so copy the part of hash data to the OutData.
 | |
|         //
 | |
|         CopyMem (OutData, OutHashData, OutDataSize);
 | |
|         Status = EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|   default:
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   if (HashContext != NULL) {
 | |
|     FreePool (HashContext);
 | |
|   }
 | |
|   if (OutHashData != NULL) {
 | |
|     FreePool (OutHashData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Digests the Payload and store the result into the OutData.
 | |
| 
 | |
|   This function calls relevant Hash interface from CryptoLib according to
 | |
|   the input algorithm ID. It computes all datas from InDataFragment and output
 | |
|   the result into the OutData buffer. If the OutDataSize is larger than the related
 | |
|   Hash algorithm output size, return EFI_INVALID_PARAMETER.
 | |
| 
 | |
|   @param[in]      AlgorithmId     The authentication Identification.
 | |
|   @param[in]      InDataFragment  A list contains all data to be authenticated.
 | |
|   @param[in]      FragmentCount   The size of the InDataFragment.
 | |
|   @param[out]     OutData         For in, the buffer to receive the output data.
 | |
|                                   For out, the buffer contains the authenticated data.
 | |
|   @param[in]      OutDataSize     The size of the buffer of OutData.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.
 | |
|   @retval EFI_SUCCESS           Authenticated the payload successfully.
 | |
|   @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash
 | |
|                                 algorithm could handle.
 | |
|   @retval otherwise             Authentication of the payload failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoHash (
 | |
|   IN     CONST UINT8              AlgorithmId,
 | |
|   IN           HASH_DATA_FRAGMENT *InDataFragment,
 | |
|   IN           UINTN              FragmentCount,
 | |
|      OUT       UINT8              *OutData,
 | |
|   IN           UINTN              OutDataSize
 | |
|   )
 | |
| {
 | |
|   UINTN        ContextSize;
 | |
|   UINTN        Index;
 | |
|   UINT8        FragmentIndex;
 | |
|   UINT8        *HashContext;
 | |
|   EFI_STATUS   Status;
 | |
|   UINT8        *OutHashData;
 | |
|   UINTN        OutHashSize;
 | |
| 
 | |
|   Status      = EFI_UNSUPPORTED;
 | |
|   OutHashData = NULL;
 | |
| 
 | |
|   OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
 | |
|   //
 | |
|   // If the expected hash data size is larger than the related Hash algorithm
 | |
|   // output length, return EFI_INVALID_PARAMETER.
 | |
|   //
 | |
|   if (OutDataSize > OutHashSize) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   OutHashData = AllocatePool (OutHashSize);
 | |
|   if (OutHashData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   switch (AlgorithmId) {
 | |
| 
 | |
|   case IKE_AALG_NONE:
 | |
|   case IKE_AALG_NULL:
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   case IKE_AALG_SHA1HMAC:
 | |
|     Index = IpSecGetIndexFromAuthList (AlgorithmId);
 | |
|     if (Index == -1) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Get Context Size
 | |
|     //
 | |
|     ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();
 | |
|     HashContext = AllocateZeroPool (ContextSize);
 | |
|     if (HashContext == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Initiate Hash context and hash the input data.
 | |
|     //
 | |
|     if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {
 | |
|       for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
 | |
|         if (!mIpsecHashAlgorithmList[Index].HashUpdate (
 | |
|                 HashContext,
 | |
|                 InDataFragment[FragmentIndex].Data,
 | |
|                 InDataFragment[FragmentIndex].DataSize
 | |
|                 )
 | |
|           ) {
 | |
|           goto Exit;
 | |
|         }
 | |
|       }
 | |
|       if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {
 | |
|         //
 | |
|         // In some cases, like the Icv computing, the Icv size might be less than
 | |
|         // the key length size, so copy the part of hash data to the OutData.
 | |
|         //
 | |
|         CopyMem (OutData, OutHashData, OutDataSize);
 | |
|         Status = EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|   default:
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   if (HashContext != NULL) {
 | |
|     FreePool (HashContext);
 | |
|   }
 | |
|   if (OutHashData != NULL) {
 | |
|     FreePool (OutHashData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generates the Diffie-Hellman public key.
 | |
| 
 | |
|   This function first initiate a DHContext, then call the DhSetParameter() to set
 | |
|   the prime and primelength, at end call the DhGenerateKey() to generates random
 | |
|   secret exponent, and computes the public key. The output returned via parameter
 | |
|   PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey
 | |
|   buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned
 | |
|   and PublicKeySize is set to the required buffer size to obtain the public key.
 | |
| 
 | |
|   @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 buffer to receive the generated
 | |
|                                   prime number.
 | |
|   @param[out]     PublicKey       Pointer to the buffer to receive generated public key.
 | |
|   @param[in, out] PublicKeySize   For in, the size of PublicKey buffer in bytes.
 | |
|                                   For out, the size of data returned in PublicKey
 | |
|                                   buffer in bytes.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The operation performs successfully.
 | |
|   @retval Otherwise               The operation is failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoDhGetPublicKey (
 | |
|   IN OUT   UINT8  **DhContext,
 | |
|   IN       UINTN  Generator,
 | |
|   IN       UINTN  PrimeLength,
 | |
|   IN CONST UINT8  *Prime,
 | |
|      OUT   UINT8  *PublicKey,
 | |
|   IN OUT   UINTN  *PublicKeySize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
| 
 | |
|   *DhContext = DhNew ();
 | |
|   ASSERT (*DhContext != NULL);
 | |
|   if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto Exit;
 | |
|   }
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| Exit:
 | |
|   if (*DhContext != NULL) {
 | |
|     DhFree (*DhContext);
 | |
|     DhContext = NULL;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generates 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.
 | |
| 
 | |
|   @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           For in, the size of Key buffer in bytes.
 | |
|                                     For out, the size of data returned in Key
 | |
|                                     buffer in bytes.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation performs successfully.
 | |
|   @retval Otherwise                The operation is failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoDhComputeKey (
 | |
|   IN   OUT   UINT8  *DhContext,
 | |
|   IN   CONST UINT8  *PeerPublicKey,
 | |
|   IN         UINTN  PeerPublicKeySize,
 | |
|        OUT   UINT8  *Key,
 | |
|   IN   OUT   UINTN  *KeySize
 | |
|   )
 | |
| {
 | |
|   if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.
 | |
| 
 | |
|   @param[in, out]     DhContext         Pointer to the DH context to be freed.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation performs successfully.
 | |
|   @retval EFI_INVALID_PARAMETER    The DhContext is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoFreeDh (
 | |
|   IN   OUT   UINT8  **DhContext
 | |
|   )
 | |
| {
 | |
|   if (*DhContext == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   DhFree (*DhContext);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generates random numbers of specified size.
 | |
| 
 | |
|   If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.
 | |
| 
 | |
|   @param[out]  OutBuffer        Pointer to buffer to receive random value.
 | |
|   @param[in]   Bytes            Size of random bytes to generate.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The operation performs successfully.
 | |
|   @retval Otherwise                The operation is failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoGenerateRandomBytes (
 | |
|   OUT UINT8*    OutBuffer,
 | |
|   IN  UINTN     Bytes
 | |
|   )
 | |
| {
 | |
|   if (!mInitialRandomSeed) {
 | |
|     RandomSeed (NULL, 0);
 | |
|     mInitialRandomSeed = TRUE;
 | |
|   }
 | |
|   if (RandomBytes (OutBuffer, Bytes)) {
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Authenticate data with the certificate.
 | |
| 
 | |
|   @param[in]      InData          Pointer to the Data to be signed.
 | |
|   @param[in]      InDataSize      InData size in bytes.
 | |
|   @param[in]      PrivateKey      Pointer to the  private key.
 | |
|   @param[in]      PrivateKeySize  The size of Private Key in bytes.
 | |
|   @param[in]      KeyPassWord     Pointer to the password for retrieving private key.
 | |
|   @param[in]      KeyPwdSize      The size of Key Password in bytes.
 | |
|   @param[out]     OutData         The pointer to the signed data.
 | |
|   @param[in, out] OutDataSize     Pointer to contain the size of out data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IpSecCryptoIoAuthDataWithCertificate (
 | |
|   IN     UINT8   *InData,
 | |
|   IN     UINTN   InDataSize,
 | |
|   IN     UINT8   *PrivateKey,
 | |
|   IN     UINTN   PrivateKeySize,
 | |
|   IN     UINT8   *KeyPassWord,
 | |
|   IN     UINTN   KeyPwdSize,
 | |
|      OUT UINT8   **OutData,
 | |
|   IN OUT UINTN   *OutDataSize
 | |
|   )
 | |
| {
 | |
|   UINT8         *RsaContext;
 | |
|   UINT8         *Signature;
 | |
|   UINTN         SigSize;
 | |
| 
 | |
|   SigSize   = 0;
 | |
|   RsaContext = NULL;
 | |
| 
 | |
|   //
 | |
|   // Retrieve RSA Private Key from password-protected PEM data
 | |
|   //
 | |
|   RsaGetPrivateKeyFromPem (
 | |
|     (CONST UINT8 *)PrivateKey,
 | |
|     PrivateKeySize,
 | |
|     (CONST CHAR8 *)KeyPassWord,
 | |
|     (VOID **) &RsaContext
 | |
|     );
 | |
|   if (RsaContext == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Sign data
 | |
|   //
 | |
|   Signature = NULL;
 | |
|   if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {
 | |
|     Signature = AllocateZeroPool (SigSize);
 | |
|   } else {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);
 | |
| 
 | |
|   *OutData     = Signature;
 | |
|   *OutDataSize = SigSize;
 | |
| 
 | |
|   if (RsaContext != NULL) {
 | |
|     RsaFree (RsaContext);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Verify the singed data with the public key which is contained in a certificate.
 | |
| 
 | |
|   @param[in]     InCert          Pointer to the Certificate which contains the
 | |
|                                  public key.
 | |
|   @param[in]     CertLen         The size of Certificate in bytes.
 | |
|   @param[in]     InCa            Pointer to the CA certificate
 | |
|   @param[in]     CaLen           The size of CA certificate in bytes.
 | |
|   @param[in]     InData          Pointer to octet message hash to be checked.
 | |
|   @param[in]     InDataSize      Size of the message hash in bytes.
 | |
|   @param[in]     Singnature      The pointer to the 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
 | |
| IpSecCryptoIoVerifySignDataByCertificate (
 | |
|   IN     UINT8   *InCert,
 | |
|   IN     UINTN   CertLen,
 | |
|   IN     UINT8   *InCa,
 | |
|   IN     UINTN   CaLen,
 | |
|   IN     UINT8   *InData,
 | |
|   IN     UINTN   InDataSize,
 | |
|   IN     UINT8   *Singnature,
 | |
|   IN     UINTN   SigSize
 | |
|   )
 | |
| {
 | |
|   UINT8         *RsaContext;
 | |
|   BOOLEAN       Status;
 | |
| 
 | |
|   //
 | |
|   // Create the RSA Context
 | |
|   //
 | |
|   RsaContext = RsaNew ();
 | |
|   if (RsaContext == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Verify the validity of X509 Certificate
 | |
|   //
 | |
|   if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve the RSA public Key from Certificate
 | |
|   //
 | |
|   RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);
 | |
| 
 | |
|   //
 | |
|   // Verify data
 | |
|   //
 | |
|   Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);
 | |
| 
 | |
|   if (RsaContext != NULL) {
 | |
|     RsaFree (RsaContext);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrieves the RSA Public Key from one X509 certificate (DER format only).
 | |
| 
 | |
|   @param[in]     InCert            Pointer to the certificate.
 | |
|   @param[in]     CertLen           The size of the certificate in bytes.
 | |
|   @param[out]    PublicKey         Pointer to the retrieved public key.
 | |
|   @param[out]    PublicKeyLen      Size of Public Key in bytes.
 | |
| 
 | |
|   @retval  EFI_SUCCESS            Successfully get the public Key.
 | |
|   @retval  EFI_INVALID_PARAMETER  The certificate is malformed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoGetPublicKeyFromCert (
 | |
|   IN     UINT8   *InCert,
 | |
|   IN     UINTN   CertLen,
 | |
|   OUT    UINT8   **PublicKey,
 | |
|   OUT    UINTN   *PublicKeyLen
 | |
|   )
 | |
| {
 | |
|   UINT8         *RsaContext;
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Create the RSA Context
 | |
|   //
 | |
|   RsaContext = RsaNew ();
 | |
| 
 | |
|   //
 | |
|   // Retrieve the RSA public key from CA Certificate
 | |
|   //
 | |
|   if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto EXIT;
 | |
|   }
 | |
| 
 | |
|   *PublicKeyLen = 0;
 | |
| 
 | |
|   RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);
 | |
| 
 | |
|   *PublicKey = AllocateZeroPool (*PublicKeyLen);
 | |
|   if (*PublicKey == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto EXIT;
 | |
|   }
 | |
| 
 | |
|   if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
| EXIT:
 | |
|   if (RsaContext != NULL) {
 | |
|     RsaFree (RsaContext);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrieves the subject name from one X509 certificate (DER format only).
 | |
| 
 | |
|   @param[in]     InCert            Pointer to the X509 certificate.
 | |
|   @param[in]     CertSize          The size of the X509 certificate in bytes.
 | |
|   @param[out]    CertSubject       Pointer to the retrieved certificate subject.
 | |
|   @param[out]    SubjectSize       The size of Certificate Subject in bytes.
 | |
| 
 | |
|   @retval  EFI_SUCCESS            Retrieved the certificate subject successfully.
 | |
|   @retval  EFI_INVALID_PARAMETER  The certificate is malformed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpSecCryptoIoGetSubjectFromCert (
 | |
|   IN     UINT8   *InCert,
 | |
|   IN     UINTN   CertSize,
 | |
|   OUT    UINT8   **CertSubject,
 | |
|   OUT    UINTN   *SubjectSize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   *SubjectSize = 0;
 | |
|   X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);
 | |
| 
 | |
|   *CertSubject = AllocateZeroPool (*SubjectSize);
 | |
|   if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |