/** @file\r
- Common operation for Security.\r
+ Common interfaces to call Security library.\r
\r
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
\r
#include "IpSecCryptIo.h"\r
//\r
-// Alogrithm's informations for the Encrypt/Decrpt Alogrithm.\r
+// The informations for the supported Encrypt/Decrpt Alogrithm.\r
//\r
-ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
{IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r
- {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL}\r
+ {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL}, \r
+ {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},\r
+ {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}\r
};\r
+\r
+//\r
+// The informations for the supported Authentication algorithm\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
+ {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+ {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+ {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}\r
+};\r
+\r
//\r
-// Alogrithm's informations for the Authentication algorithm\r
+// The information for the supported Hash aglorithm\r
//\r
-AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {\r
{IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
{IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
- {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL}\r
+ {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}\r
};\r
\r
+BOOLEAN mInitialRandomSeed = FALSE;\r
\r
/**\r
- Get the block size of encrypt alogrithm. The block size is based on the algorithm used.\r
+ Get the block size of specified encryption alogrithm.\r
\r
- @param[in] AlgorithmId The encrypt algorithm ID.\r
+ @param[in] AlgorithmId The encryption algorithm ID.\r
\r
@return The value of block size.\r
\r
\r
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
- //\r
- // The BlockSize is same with IvSize.\r
- //\r
return mIpsecEncryptAlgorithmList[Index].BlockSize;\r
}\r
}\r
}\r
\r
/**\r
- Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used.\r
+ Get the key length of the specified encryption alogrithm.\r
+\r
+ @param[in] AlgorithmId The encryption algorithm ID.\r
+\r
+ @return The value of key length.\r
+\r
+**/\r
+UINTN\r
+IpSecGetEncryptKeyLength (\r
+ IN UINT8 AlgorithmId\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+ return mIpsecEncryptAlgorithmList[Index].KeyLength;\r
+ }\r
+ }\r
+\r
+ return (UINTN) -1;\r
+}\r
+\r
+/**\r
+ Get the IV size of the specified encryption alogrithm.\r
\r
- @param[in] AlgorithmId The encrypt algorithm ID.\r
+ @param[in] AlgorithmId The encryption algorithm ID.\r
\r
@return The value of IV size.\r
\r
\r
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
- //\r
- // The BlockSize is same with IvSize.\r
- //\r
return mIpsecEncryptAlgorithmList[Index].IvLength;\r
}\r
}\r
}\r
\r
/**\r
- Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used.\r
+ Get the HMAC digest length by the specified Algorithm ID.\r
+\r
+ @param[in] AlgorithmId The specified Alogrithm ID.\r
+\r
+ @return The digest length of the specified Authentication Algorithm ID.\r
+\r
+**/\r
+UINTN\r
+IpSecGetHmacDigestLength (\r
+ IN UINT8 AlgorithmId\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+ if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {\r
+ //\r
+ // Return the Digest Length of the Algorithm.\r
+ //\r
+ return mIpsecAuthAlgorithmList[Index].DigestLength;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Get the ICV size of the specified Authenticaion alogrithm.\r
\r
- @param[in] AuthAlgorithmId The Authentication algorithm ID.\r
+ @param[in] AlgorithmId The Authentication algorithm ID.\r
\r
@return The value of ICV size.\r
\r
**/\r
UINTN\r
IpSecGetIcvLength (\r
- IN UINT8 AuthAlgorithmId\r
+ IN UINT8 AlgorithmId\r
)\r
{\r
UINT8 Index;\r
+\r
for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
- if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+ if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
return mIpsecAuthAlgorithmList[Index].IcvLength;\r
}\r
}\r
+\r
return (UINTN) -1;\r
}\r
\r
IV and return EFI_SUCCESS.\r
\r
@param[in] IvBuffer The pointer of the IV buffer.\r
- @param[in] IvSize The IV size.\r
+ @param[in] IvSize The IV size in bytes.\r
\r
@retval EFI_SUCCESS Create a random data for IV.\r
\r
)\r
{\r
if (IvSize != 0) {\r
+ return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList.\r
+\r
+ @param[in] AlgorithmId The encryption algorithm ID.\r
+\r
+ @return the index.\r
+ \r
+**/\r
+UINTN\r
+IpSecGetIndexFromEncList (\r
+ IN UINT8 AlgorithmId\r
+ )\r
+{\r
+ UINT8 Index;\r
+ \r
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+ return Index;\r
+ }\r
+ }\r
+ \r
+ return (UINTN) -1;\r
+}\r
+\r
+/**\r
+ Get index of the specified encryption alogrithm from the mIpsecAuthAlgorithemList.\r
+\r
+ @param[in] AlgorithmId The encryption algorithm ID.\r
+\r
+ @return the index.\r
+ \r
+**/\r
+UINTN\r
+IpSecGetIndexFromAuthList (\r
+ IN UINT8 AlgorithmId\r
+ )\r
+{\r
+ UINT8 Index;\r
+ \r
+ for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+ if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+ //\r
+ // The BlockSize is same with IvSize.\r
+ //\r
+ return Index;\r
+ }\r
+ }\r
+ \r
+ return (UINTN) -1;\r
+}\r
+\r
+/**\r
+ Encrypt the buffer.\r
+\r
+ This function calls relevant encryption interface from CryptoLib according to\r
+ the input alogrithm ID. The InData should be multiple of block size. This function\r
+ doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+ same with the block size. The block size is different from the different algorithm.\r
+\r
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.\r
+ @param[in] Key Pointer to the buffer containing encrypting key.\r
+ @param[in] KeyBits The length of the key in bits.\r
+ @param[in] Ivec Point to the buffer containning the Initializeion\r
+ Vector (IV) data.\r
+ @param[in] InData Point to the buffer containing the data to be\r
+ encrypted.\r
+ @param[in] InDataLength The length of InData in Bytes.\r
+ @param[out] OutData Point to the buffer that receives the encryption\r
+ output.\r
+\r
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.\r
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoEncrypt (\r
+ IN CONST UINT8 AlgorithmId,\r
+ IN CONST UINT8 *Key,\r
+ IN CONST UINTN KeyBits,\r
+ IN CONST UINT8 *Ivec, OPTIONAL\r
+ IN UINT8 *InData,\r
+ IN UINTN InDataLength,\r
+ OUT UINT8 *OutData\r
+ )\r
+{ \r
+ UINTN Index;\r
+ UINTN ContextSize;\r
+ UINT8 *Context;\r
+ EFI_STATUS Status;\r
+ \r
+ Status = EFI_UNSUPPORTED;\r
+ \r
+ switch (AlgorithmId) {\r
+\r
+ case IKE_EALG_NULL:\r
+ case IKE_EALG_NONE:\r
+ CopyMem (OutData, InData, InDataLength);\r
+ return EFI_SUCCESS;\r
+\r
+ case IKE_EALG_3DESCBC:\r
+ case IKE_EALG_AESCBC:\r
+ Index = IpSecGetIndexFromEncList (AlgorithmId);\r
+ if (Index == -1) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get Context Size\r
+ //\r
+ ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();\r
+ Context = AllocateZeroPool (ContextSize);\r
+\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
//\r
- //TODO: return CryptGenerateRandom (IvBuffer, IvSize);\r
+ // Initiate Context\r
//\r
+ if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+ if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return Status;\r
+\r
+ }\r
+\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ Decrypts the buffer.\r
+\r
+ This function calls relevant Decryption interface from CryptoLib according to\r
+ the input alogrithm ID. The InData should be multiple of block size. This function\r
+ doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+ same with the block size. The block size is different from the different algorithm.\r
+\r
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.\r
+ @param[in] Key Pointer to the buffer containing encrypting key.\r
+ @param[in] KeyBits The length of the key in bits.\r
+ @param[in] Ivec Point to the buffer containning the Initializeion\r
+ Vector (IV) data.\r
+ @param[in] InData Point to the buffer containing the data to be\r
+ decrypted.\r
+ @param[in] InDataLength The length of InData in Bytes.\r
+ @param[out] OutData Pointer to the buffer that receives the decryption\r
+ output.\r
+\r
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.\r
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDecrypt (\r
+ IN CONST UINT8 AlgorithmId,\r
+ IN CONST UINT8 *Key,\r
+ IN CONST UINTN KeyBits,\r
+ IN CONST UINT8 *Ivec, OPTIONAL\r
+ IN UINT8 *InData,\r
+ IN UINTN InDataLength,\r
+ OUT UINT8 *OutData\r
+ )\r
+{ \r
+ UINTN Index;\r
+ UINTN ContextSize;\r
+ UINT8 *Context;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ switch (AlgorithmId) {\r
+\r
+ case IKE_EALG_NULL:\r
+ case IKE_EALG_NONE:\r
+ CopyMem (OutData, InData, InDataLength);\r
return EFI_SUCCESS;\r
+\r
+ case IKE_EALG_3DESCBC:\r
+ case IKE_EALG_AESCBC:\r
+ Index = IpSecGetIndexFromEncList(AlgorithmId);\r
+ if (Index == -1) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get Context Size\r
+ //\r
+ ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();\r
+ Context = AllocateZeroPool (ContextSize);\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initiate Context\r
+ //\r
+ if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+ if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+ Status = EFI_SUCCESS; \r
+ }\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return Status;\r
+ }\r
+\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
}\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Digests the Payload with key and store the result into the OutData.\r
+\r
+ This function calls relevant Hmac interface from CryptoLib according to\r
+ the input alogrithm ID. It computes all datas from InDataFragment and output\r
+ the result into the OutData buffer. If the OutDataSize is larger than the related\r
+ HMAC alogrithm output size, return EFI_INVALID_PARAMETER.\r
+ \r
+ @param[in] AlgorithmId The authentication Identification.\r
+ @param[in] Key Pointer of the authentication key.\r
+ @param[in] KeyLength The length of the Key in bytes.\r
+ @param[in] InDataFragment The list contains all data to be authenticated.\r
+ @param[in] FragmentCount The size of the InDataFragment.\r
+ @param[out] OutData For in, the buffer to receive the output data.\r
+ For out, the buffer contains the authenticated data.\r
+ @param[in] OutDataSize The size of the buffer of OutData.\r
+\r
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.\r
+ @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.\r
+ @retval EFI_SUCCESS Authenticate the payload successfully.\r
+ @retval otherwise Authentication of the payload fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHmac (\r
+ IN CONST UINT8 AlgorithmId,\r
+ IN CONST UINT8 *Key,\r
+ IN UINTN KeyLength,\r
+ IN HASH_DATA_FRAGMENT *InDataFragment,\r
+ IN UINTN FragmentCount,\r
+ OUT UINT8 *OutData,\r
+ IN UINTN OutDataSize\r
+ )\r
+{\r
+ UINTN ContextSize;\r
+ UINTN Index;\r
+ UINT8 FragmentIndex;\r
+ UINT8 *HashContext;\r
+ EFI_STATUS Status;\r
+ UINT8 *OutHashData;\r
+ UINTN OutHashSize;\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ OutHashData = NULL;\r
+\r
+ OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+ //\r
+ // If the expected hash data size is larger than the related Hash algorithm\r
+ // output length, return EFI_INVALID_PARAMETER.\r
+ //\r
+ if (OutDataSize > OutHashSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ OutHashData = AllocatePool (OutHashSize);\r
+\r
+ if (OutHashData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ switch (AlgorithmId) {\r
+\r
+ case IKE_AALG_NONE :\r
+ case IKE_AALG_NULL :\r
+ return EFI_SUCCESS;\r
+\r
+ case IKE_AALG_SHA1HMAC:\r
+ Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+ if (Index == -1) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get Context Size\r
+ //\r
+ ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();\r
+ HashContext = AllocateZeroPool (ContextSize);\r
+\r
+ if (HashContext == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Initiate HMAC context and hash the input data.\r
+ //\r
+ if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {\r
+ for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+ if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (\r
+ HashContext,\r
+ InDataFragment[FragmentIndex].Data,\r
+ InDataFragment[FragmentIndex].DataSize\r
+ )\r
+ ) {\r
+ goto Exit;\r
+ }\r
+ }\r
+ if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {\r
+ //\r
+ // In some cases, like the Icv computing, the Icv size might be less than\r
+ // the key length size, so copy the part of hash data to the OutData.\r
+ //\r
+ CopyMem (OutData, OutHashData, OutDataSize);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ goto Exit;\r
+ } \r
+ \r
+ default:\r
+ return Status;\r
+ }\r
+\r
+Exit:\r
+ if (HashContext != NULL) {\r
+ FreePool (HashContext);\r
+ }\r
+ if (OutHashData != NULL) {\r
+ FreePool (OutHashData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Digests the Payload and store the result into the OutData.\r
+\r
+ This function calls relevant Hash interface from CryptoLib according to\r
+ the input alogrithm ID. It computes all datas from InDataFragment and output\r
+ the result into the OutData buffer. If the OutDataSize is larger than the related\r
+ Hash alogrithm output size, return EFI_INVALID_PARAMETER.\r
+\r
+ @param[in] AlgorithmId The authentication Identification.\r
+ @param[in] InDataFragment A list contains all data to be authenticated.\r
+ @param[in] FragmentCount The size of the InDataFragment.\r
+ @param[out] OutData For in, the buffer to receive the output data.\r
+ For out, the buffer contains the authenticated data.\r
+ @param[in] OutDataSize The size of the buffer of OutData.\r
+\r
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.\r
+ @retval EFI_SUCCESS Authenticated the payload successfully.\r
+ @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash\r
+ algorithm could handle.\r
+ @retval otherwise Authentication of the payload failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHash (\r
+ IN CONST UINT8 AlgorithmId,\r
+ IN HASH_DATA_FRAGMENT *InDataFragment,\r
+ IN UINTN FragmentCount,\r
+ OUT UINT8 *OutData,\r
+ IN UINTN OutDataSize\r
+ )\r
+{\r
+ UINTN ContextSize;\r
+ UINTN Index;\r
+ UINT8 FragmentIndex;\r
+ UINT8 *HashContext;\r
+ EFI_STATUS Status;\r
+ UINT8 *OutHashData;\r
+ UINTN OutHashSize;\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ OutHashData = NULL;\r
+ \r
+ OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+ //\r
+ // If the expected hash data size is larger than the related Hash algorithm\r
+ // output length, return EFI_INVALID_PARAMETER. \r
+ //\r
+ if (OutDataSize > OutHashSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ OutHashData = AllocatePool (OutHashSize);\r
+ if (OutHashData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ switch (AlgorithmId) {\r
+\r
+ case IKE_AALG_NONE:\r
+ case IKE_AALG_NULL:\r
+ return EFI_SUCCESS;\r
+\r
+ case IKE_AALG_SHA1HMAC:\r
+ Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+ if (Index == -1) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get Context Size\r
+ //\r
+ ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();\r
+ HashContext = AllocateZeroPool (ContextSize);\r
+ if (HashContext == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+ \r
+ //\r
+ // Initiate Hash context and hash the input data.\r
+ //\r
+ if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {\r
+ for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+ if (!mIpsecHashAlgorithmList[Index].HashUpdate (\r
+ HashContext,\r
+ InDataFragment[FragmentIndex].Data,\r
+ InDataFragment[FragmentIndex].DataSize\r
+ )\r
+ ) {\r
+ goto Exit;\r
+ }\r
+ }\r
+ if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {\r
+ //\r
+ // In some cases, like the Icv computing, the Icv size might be less than\r
+ // the key length size, so copy the part of hash data to the OutData.\r
+ //\r
+ CopyMem (OutData, OutHashData, OutDataSize); \r
+ Status = EFI_SUCCESS;\r
+ }\r
+ \r
+ goto Exit; \r
+ } \r
+ \r
+ default:\r
+ return Status;\r
+ }\r
+\r
+Exit:\r
+ if (HashContext != NULL) {\r
+ FreePool (HashContext);\r
+ }\r
+ if (OutHashData != NULL) {\r
+ FreePool (OutHashData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Generates the Diffie-Hellman public key.\r
+\r
+ This function first initiate a DHContext, then call the DhSetParameter() to set\r
+ the prime and primelenght, at end call the DhGenerateKey() to generates random\r
+ secret exponent, and computes the public key. The output returned via parameter\r
+ PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey\r
+ buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned\r
+ and PublicKeySize is set to the required buffer size to obtain the public key.\r
+\r
+ @param[in, out] DhContext Pointer to the DH context.\r
+ @param[in] Generator Vlaue of generator.\r
+ @param[in] PrimeLength Length in bits of prime to be generated.\r
+ @param[in] Prime Pointer to the buffer to receive the generated\r
+ prime number.\r
+ @param[out] PublicKey Pointer to the buffer to receive generated public key.\r
+ @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes.\r
+ For out, the size of data returned in PublicKey\r
+ buffer in bytes.\r
+\r
+ @retval EFI_SUCCESS The operation perfoms successfully.\r
+ @retval Otherwise The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhGetPublicKey (\r
+ IN OUT UINT8 **DhContext,\r
+ IN UINTN Generator,\r
+ IN UINTN PrimeLength,\r
+ IN CONST UINT8 *Prime,\r
+ OUT UINT8 *PublicKey,\r
+ IN OUT UINTN *PublicKeySize\r
+ ) \r
+{\r
+ EFI_STATUS Status;\r
+ \r
+ *DhContext = DhNew ();\r
+ ASSERT (*DhContext != NULL);\r
+ if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+ return EFI_SUCCESS;\r
+\r
+Exit:\r
+ if (*DhContext != NULL) {\r
+ DhFree (*DhContext);\r
+ DhContext = NULL;\r
+ }\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ Generates exchanged common key.\r
+\r
+ Given peer's public key, this function computes the exchanged common key, based\r
+ on its own context including value of prime modulus and random secret exponent.\r
+\r
+ @param[in, out] DhContext Pointer to the DH context.\r
+ @param[in] PeerPublicKey Pointer to the peer's Public Key.\r
+ @param[in] PeerPublicKeySize Size of peer's public key in bytes.\r
+ @param[out] Key Pointer to the buffer to receive generated key.\r
+ @param[in, out] KeySize For in, the size of Key buffer in bytes.\r
+ For out, the size of data returned in Key\r
+ buffer in bytes.\r
+\r
+ @retval EFI_SUCCESS The operation perfoms successfully.\r
+ @retval Otherwise The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhComputeKey (\r
+ IN OUT UINT8 *DhContext, \r
+ IN CONST UINT8 *PeerPublicKey,\r
+ IN UINTN PeerPublicKeySize,\r
+ OUT UINT8 *Key,\r
+ IN OUT UINTN *KeySize\r
+ )\r
+{\r
+ if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.\r
+\r
+ @param[in, out] DhContext Pointer to the DH context to be freed.\r
+\r
+ @retval EFI_SUCCESS The operation perfoms successfully.\r
+ @retval EFI_INVALID_PARAMETER The DhContext is NULL.\r
+ \r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoFreeDh (\r
+ IN OUT UINT8 **DhContext\r
+ )\r
+{ \r
+ if (*DhContext == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DhFree (*DhContext);\r
return EFI_SUCCESS;\r
}\r
+\r
+/**\r
+ Generates random numbers of specified size.\r
+\r
+ If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.\r
+\r
+ @param[out] OutBuffer Pointer to buffer to receive random value.\r
+ @param[in] Bytes Size of randome bytes to generate.\r
+\r
+ @retval EFI_SUCCESS The operation perfoms successfully.\r
+ @retval Otherwise The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGenerateRandomBytes (\r
+ OUT UINT8* OutBuffer,\r
+ IN UINTN Bytes\r
+ )\r
+{\r
+ if (!mInitialRandomSeed) {\r
+ RandomSeed (NULL, 0);\r
+ mInitialRandomSeed = TRUE;\r
+ }\r
+ if (RandomBytes (OutBuffer, Bytes)) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+}\r
+\r
+/**\r
+ Authenticate data with the certificate.\r
+\r
+ @param[in] InData Pointer to the Data to be signed.\r
+ @param[in] InDataSize InData size in bytes.\r
+ @param[in] PrivateKey Pointer to the private key.\r
+ @param[in] PrivateKeySize The size of Private Key in bytes.\r
+ @param[in] KeyPassWord Pointer to the password for retrieving private key.\r
+ @param[in] KeyPwdSize The size of Key Password in bytes.\r
+ @param[out] OutData The pointer to the signed data.\r
+ @param[in, out] OutDataSize Pointer to contain the size of out data.\r
+ \r
+**/\r
+VOID\r
+IpSecCryptoIoAuthDataWithCertificate (\r
+ IN UINT8 *InData,\r
+ IN UINTN InDataSize,\r
+ IN UINT8 *PrivateKey,\r
+ IN UINTN PrivateKeySize,\r
+ IN UINT8 *KeyPassWord,\r
+ IN UINTN KeyPwdSize,\r
+ OUT UINT8 **OutData,\r
+ IN OUT UINTN *OutDataSize\r
+ )\r
+{\r
+ UINT8 *RsaContext;\r
+ UINT8 *Signature;\r
+ UINTN SigSize;\r
+ \r
+ SigSize = 0;\r
+ //\r
+ // Retrieve RSA Private Key from password-protected PEM data\r
+ //\r
+ RsaGetPrivateKeyFromPem (\r
+ (CONST UINT8 *)PrivateKey,\r
+ PrivateKeySize,\r
+ (CONST CHAR8 *)KeyPassWord,\r
+ (VOID **) &RsaContext\r
+ );\r
+ if (RsaContext == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Sign data\r
+ //\r
+ Signature = NULL; \r
+ if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {\r
+ Signature = AllocateZeroPool (SigSize);\r
+ } else {\r
+ return;\r
+ } \r
+\r
+ RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);\r
+\r
+ *OutData = Signature;\r
+ *OutDataSize = SigSize;\r
+\r
+ if (RsaContext != NULL) {\r
+ RsaFree (RsaContext);\r
+ }\r
+}\r
+\r
+/**\r
+ Verify the singed data with the public key which is contained in a certificate.\r
+\r
+ @param[in] InCert Pointer to the Certificate which contains the\r
+ public key.\r
+ @param[in] CertLen The size of Certificate in bytes.\r
+ @param[in] InCa Pointer to the CA certificate\r
+ @param[in] CaLen The size of CA certificate in bytes.\r
+ @param[in] InData Pointer to octect message hash to be checked.\r
+ @param[in] InDataSize Size of the message hash in bytes.\r
+ @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verifed.\r
+ @param[in] SigSize Size of signature in bytes.\r
+\r
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.\r
+ @retval FALSE Invalid signature or invalid RSA context.\r
+ \r
+**/\r
+BOOLEAN\r
+IpSecCryptoIoVerifySignDataByCertificate (\r
+ IN UINT8 *InCert,\r
+ IN UINTN CertLen,\r
+ IN UINT8 *InCa,\r
+ IN UINTN CaLen,\r
+ IN UINT8 *InData,\r
+ IN UINTN InDataSize,\r
+ IN UINT8 *Singnature,\r
+ IN UINTN SigSize\r
+ )\r
+{\r
+ UINT8 *RsaContext;\r
+ BOOLEAN Status;\r
+\r
+ //\r
+ // Create the RSA Context\r
+ //\r
+ RsaContext = RsaNew ();\r
+ if (RsaContext == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Verify the validity of X509 Certificate\r
+ //\r
+ if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Retrieve the RSA public Key from Certificate\r
+ //\r
+ RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);\r
+ \r
+ //\r
+ // Verify data\r
+ //\r
+ Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);\r
+\r
+ if (RsaContext != NULL) {\r
+ RsaFree (RsaContext);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the RSA Public Key from one X509 certificate (DER format only).\r
+\r
+ @param[in] InCert Pointer to the certificate.\r
+ @param[in] CertLen The size of the certificate in bytes.\r
+ @param[out] PublicKey Pointer to the retrieved public key.\r
+ @param[out] PublicKeyLen Size of Public Key in bytes.\r
+\r
+ @retval EFI_SUCCESS Successfully get the public Key.\r
+ @retval EFI_INVALID_PARAMETER The certificate is malformed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetPublicKeyFromCert (\r
+ IN UINT8 *InCert,\r
+ IN UINTN CertLen,\r
+ OUT UINT8 **PublicKey,\r
+ OUT UINTN *PublicKeyLen\r
+ )\r
+{\r
+ UINT8 *RsaContext;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Create the RSA Context\r
+ //\r
+ RsaContext = RsaNew ();\r
+\r
+ //\r
+ // Retrieve the RSA public key from CA Certificate\r
+ //\r
+ if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto EXIT;\r
+ }\r
+\r
+ *PublicKeyLen = 0;\r
+ \r
+ RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);\r
+ \r
+ *PublicKey = AllocateZeroPool (*PublicKeyLen);\r
+ ASSERT (*PublicKey != NULL);\r
+\r
+ if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+EXIT:\r
+ if (RsaContext != NULL) {\r
+ RsaFree (RsaContext);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the subject name from one X509 certificate (DER format only).\r
+\r
+ @param[in] InCert Pointer to the X509 certificate.\r
+ @param[in] CertSize The size of the X509 certificate in bytes.\r
+ @param[out] CertSubject Pointer to the retrieved certificate subject.\r
+ @param[out] SubjectSize The size of Certificate Subject in bytes.\r
+ \r
+ @retval EFI_SUCCESS Retrieved the certificate subject successfully.\r
+ @retval EFI_INVALID_PARAMETER The certificate is malformed.\r
+ \r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetSubjectFromCert (\r
+ IN UINT8 *InCert,\r
+ IN UINTN CertSize,\r
+ OUT UINT8 **CertSubject,\r
+ OUT UINTN *SubjectSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ *SubjectSize = 0;\r
+ X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);\r
+\r
+ *CertSubject = AllocateZeroPool (*SubjectSize);\r
+ if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r