From 9166f840d2a70b924b0ff66528f056515443e4e8 Mon Sep 17 00:00:00 2001 From: qianouyang Date: Fri, 31 Dec 2010 10:43:54 +0000 Subject: Add IPsec/Ikev2 support. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/IpSecCryptIo.c | 929 ++++++++++++++++++++++++++++++++++++- 1 file changed, 906 insertions(+), 23 deletions(-) (limited to 'NetworkPkg/IpSecDxe/IpSecCryptIo.c') diff --git a/NetworkPkg/IpSecDxe/IpSecCryptIo.c b/NetworkPkg/IpSecDxe/IpSecCryptIo.c index 93b69a6682..027e078e7a 100644 --- a/NetworkPkg/IpSecDxe/IpSecCryptIo.c +++ b/NetworkPkg/IpSecDxe/IpSecCryptIo.c @@ -1,5 +1,5 @@ /** @file - Common operation for Security. + Common interfaces to call Security library. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
@@ -15,26 +15,39 @@ #include "IpSecCryptIo.h" // -// Alogrithm's informations for the Encrypt/Decrpt Alogrithm. +// The informations for the supported Encrypt/Decrpt Alogrithm. // -ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = { +GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = { {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL}, - {(UINT8)-1, 0, 0, 0, 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} +}; + // -// Alogrithm's informations for the Authentication algorithm +// The information for the supported Hash aglorithm // -AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = { +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}, - {(UINT8)-1, 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 encrypt alogrithm. The block size is based on the algorithm used. + Get the block size of specified encryption alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of block size. @@ -48,9 +61,6 @@ IpSecGetEncryptBlockSize ( for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { - // - // The BlockSize is same with IvSize. - // return mIpsecEncryptAlgorithmList[Index].BlockSize; } } @@ -59,9 +69,33 @@ IpSecGetEncryptBlockSize ( } /** - Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used. + Get the key length of the specified encryption alogrithm. + + @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 alogrithm. - @param[in] AlgorithmId The encrypt algorithm ID. + @param[in] AlgorithmId The encryption algorithm ID. @return The value of IV size. @@ -75,9 +109,6 @@ IpSecGetEncryptIvLength ( for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { - // - // The BlockSize is same with IvSize. - // return mIpsecEncryptAlgorithmList[Index].IvLength; } } @@ -86,24 +117,53 @@ IpSecGetEncryptIvLength ( } /** - Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used. + 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 alogrithm. - @param[in] AuthAlgorithmId The Authentication algorithm ID. + @param[in] AlgorithmId The Authentication algorithm ID. @return The value of ICV size. **/ UINTN IpSecGetIcvLength ( - IN UINT8 AuthAlgorithmId + IN UINT8 AlgorithmId ) { UINT8 Index; + for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) { - if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { + if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { return mIpsecAuthAlgorithmList[Index].IcvLength; } } + return (UINTN) -1; } @@ -112,7 +172,7 @@ IpSecGetIcvLength ( IV and return EFI_SUCCESS. @param[in] IvBuffer The pointer of the IV buffer. - @param[in] IvSize The IV size. + @param[in] IvSize The IV size in bytes. @retval EFI_SUCCESS Create a random data for IV. @@ -124,10 +184,833 @@ IpSecGenerateIv ( ) { if (IvSize != 0) { + return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize); + } + + return EFI_SUCCESS; +} + +/** + Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList. + + @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 alogrithm from the mIpsecAuthAlgorithemList. + + @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 alogrithm 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 Alogrithem 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 containning the Initializeion + 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; + } // - //TODO: return CryptGenerateRandom (IvBuffer, IvSize); + // 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 alogrithm 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 Alogrithem 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 containning the Initializeion + 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 alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + HMAC alogrithm 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 alogrithm ID. It computes all datas from InDataFragment and output + the result into the OutData buffer. If the OutDataSize is larger than the related + Hash alogrithm 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 primelenght, 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 Vlaue 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 perfoms 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 perfoms 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 perfoms 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 randome bytes to generate. + + @retval EFI_SUCCESS The operation perfoms 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; + // + // 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] InCertLen 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 octect 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 verifed. + @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); + ASSERT (*PublicKey != NULL); + + 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; +} -- cgit v1.2.3