diff options
Diffstat (limited to 'Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c')
-rw-r--r-- | Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c new file mode 100644 index 0000000000..31fa4fb447 --- /dev/null +++ b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c @@ -0,0 +1,1021 @@ +/** @file
+ Common interfaces to call Security library.
+
+ Copyright (c) 2009 - 2016, 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;
+}
|