| /** @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; | |
| } |