/** @file The Miscellaneous Routines for TlsDxe driver. Copyright (c) 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 "TlsImpl.h" /** Encrypt the message listed in fragment. @param[in] TlsInstance The pointer to the TLS instance. @param[in, out] FragmentTable Pointer to a list of fragment. On input these fragments contain the TLS header and plain text TLS payload; On output these fragments contain the TLS header and cipher text TLS payload. @param[in] FragmentCount Number of fragment. @retval EFI_SUCCESS The operation completed successfully. @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. @retval EFI_ABORTED TLS session state is incorrect. @retval Others Other errors as indicated. **/ EFI_STATUS TlsEncryptPacket ( IN TLS_INSTANCE *TlsInstance, IN OUT EFI_TLS_FRAGMENT_DATA **FragmentTable, IN UINT32 *FragmentCount ) { EFI_STATUS Status; UINTN Index; UINT32 BytesCopied; UINT32 BufferInSize; UINT8 *BufferIn; UINT8 *BufferInPtr; TLS_RECORD_HEADER *RecordHeaderIn; UINT16 ThisPlainMessageSize; TLS_RECORD_HEADER *TempRecordHeader; UINT16 ThisMessageSize; UINT32 BufferOutSize; UINT8 *BufferOut; INTN Ret; Status = EFI_SUCCESS; BytesCopied = 0; BufferInSize = 0; BufferIn = NULL; BufferInPtr = NULL; RecordHeaderIn = NULL; TempRecordHeader = NULL; BufferOutSize = 0; BufferOut = NULL; Ret = 0; // // Calculate the size according to the fragment table. // for (Index = 0; Index < *FragmentCount; Index++) { BufferInSize += (*FragmentTable)[Index].FragmentLength; } // // Allocate buffer for processing data. // BufferIn = AllocateZeroPool (BufferInSize); if (BufferIn == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } // // Copy all TLS plain record header and payload into BufferIn. // for (Index = 0; Index < *FragmentCount; Index++) { CopyMem ( (BufferIn + BytesCopied), (*FragmentTable)[Index].FragmentBuffer, (*FragmentTable)[Index].FragmentLength ); BytesCopied += (*FragmentTable)[Index].FragmentLength; } BufferOut = AllocateZeroPool (MAX_BUFFER_SIZE); if (BufferOut == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } // // Parsing buffer. // BufferInPtr = BufferIn; TempRecordHeader = (TLS_RECORD_HEADER *) BufferOut; while ((UINTN) BufferInPtr < (UINTN) BufferIn + BufferInSize) { RecordHeaderIn = (TLS_RECORD_HEADER *) BufferInPtr; if (RecordHeaderIn->ContentType != TLS_CONTENT_TYPE_APPLICATION_DATA) { Status = EFI_INVALID_PARAMETER; goto ERROR; } ThisPlainMessageSize = RecordHeaderIn->Length; TlsWrite (TlsInstance->TlsConn, (UINT8 *) (RecordHeaderIn + 1), ThisPlainMessageSize); Ret = TlsCtrlTrafficOut (TlsInstance->TlsConn, (UINT8 *)(TempRecordHeader), MAX_BUFFER_SIZE - BufferOutSize); if (Ret > 0) { ThisMessageSize = (UINT16) Ret; } else { // // No data was successfully encrypted, continue to encrypt other messages. // DEBUG ((EFI_D_WARN, "TlsEncryptPacket: No data read from TLS object.\n")); ThisMessageSize = 0; } BufferOutSize += ThisMessageSize; BufferInPtr += RECORD_HEADER_LEN + ThisPlainMessageSize; TempRecordHeader += ThisMessageSize; } FreePool (BufferIn); BufferIn = NULL; // // The caller will be responsible to handle the original fragment table. // *FragmentTable = AllocateZeroPool (sizeof (EFI_TLS_FRAGMENT_DATA)); if (*FragmentTable == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } (*FragmentTable)[0].FragmentBuffer = BufferOut; (*FragmentTable)[0].FragmentLength = BufferOutSize; *FragmentCount = 1; return Status; ERROR: if (BufferIn != NULL) { FreePool (BufferIn); BufferIn = NULL; } if (BufferOut != NULL) { FreePool (BufferOut); BufferOut = NULL; } return Status; } /** Decrypt the message listed in fragment. @param[in] TlsInstance The pointer to the TLS instance. @param[in, out] FragmentTable Pointer to a list of fragment. On input these fragments contain the TLS header and cipher text TLS payload; On output these fragments contain the TLS header and plain text TLS payload. @param[in] FragmentCount Number of fragment. @retval EFI_SUCCESS The operation completed successfully. @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. @retval EFI_ABORTED TLS session state is incorrect. @retval Others Other errors as indicated. **/ EFI_STATUS TlsDecryptPacket ( IN TLS_INSTANCE *TlsInstance, IN OUT EFI_TLS_FRAGMENT_DATA **FragmentTable, IN UINT32 *FragmentCount ) { EFI_STATUS Status; UINTN Index; UINT32 BytesCopied; UINT8 *BufferIn; UINT32 BufferInSize; UINT8 *BufferInPtr; TLS_RECORD_HEADER *RecordHeaderIn; UINT16 ThisCipherMessageSize; TLS_RECORD_HEADER *TempRecordHeader; UINT16 ThisPlainMessageSize; UINT8 *BufferOut; UINT32 BufferOutSize; INTN Ret; Status = EFI_SUCCESS; BytesCopied = 0; BufferIn = NULL; BufferInSize = 0; BufferInPtr = NULL; RecordHeaderIn = NULL; TempRecordHeader = NULL; BufferOut = NULL; BufferOutSize = 0; Ret = 0; // // Calculate the size according to the fragment table. // for (Index = 0; Index < *FragmentCount; Index++) { BufferInSize += (*FragmentTable)[Index].FragmentLength; } // // Allocate buffer for processing data // BufferIn = AllocateZeroPool (BufferInSize); if (BufferIn == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } // // Copy all TLS plain record header and payload to BufferIn // for (Index = 0; Index < *FragmentCount; Index++) { CopyMem ( (BufferIn + BytesCopied), (*FragmentTable)[Index].FragmentBuffer, (*FragmentTable)[Index].FragmentLength ); BytesCopied += (*FragmentTable)[Index].FragmentLength; } BufferOut = AllocateZeroPool (MAX_BUFFER_SIZE); if (BufferOut == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } // // Parsing buffer. Received packet may have multiple TLS record messages. // BufferInPtr = BufferIn; TempRecordHeader = (TLS_RECORD_HEADER *) BufferOut; while ((UINTN) BufferInPtr < (UINTN) BufferIn + BufferInSize) { RecordHeaderIn = (TLS_RECORD_HEADER *) BufferInPtr; if (RecordHeaderIn->ContentType != TLS_CONTENT_TYPE_APPLICATION_DATA) { Status = EFI_INVALID_PARAMETER; goto ERROR; } ThisCipherMessageSize = NTOHS (RecordHeaderIn->Length); Ret = TlsCtrlTrafficIn (TlsInstance->TlsConn, (UINT8 *) (RecordHeaderIn), RECORD_HEADER_LEN + ThisCipherMessageSize); if (Ret != RECORD_HEADER_LEN + ThisCipherMessageSize) { TlsInstance->TlsSessionState = EfiTlsSessionError; Status = EFI_ABORTED; goto ERROR; } Ret = 0; Ret = TlsRead (TlsInstance->TlsConn, (UINT8 *) (TempRecordHeader + 1), MAX_BUFFER_SIZE - BufferOutSize); if (Ret > 0) { ThisPlainMessageSize = (UINT16) Ret; } else { // // No data was successfully decrypted, continue to decrypt other messages. // DEBUG ((EFI_D_WARN, "TlsDecryptPacket: No data read from TLS object.\n")); ThisPlainMessageSize = 0; } CopyMem (TempRecordHeader, RecordHeaderIn, RECORD_HEADER_LEN); TempRecordHeader->Length = ThisPlainMessageSize; BufferOutSize += RECORD_HEADER_LEN + ThisPlainMessageSize; BufferInPtr += RECORD_HEADER_LEN + ThisCipherMessageSize; TempRecordHeader += RECORD_HEADER_LEN + ThisPlainMessageSize; } FreePool (BufferIn); BufferIn = NULL; // // The caller will be responsible to handle the original fragment table // *FragmentTable = AllocateZeroPool (sizeof (EFI_TLS_FRAGMENT_DATA)); if (*FragmentTable == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR; } (*FragmentTable)[0].FragmentBuffer = BufferOut; (*FragmentTable)[0].FragmentLength = BufferOutSize; *FragmentCount = 1; return Status; ERROR: if (BufferIn != NULL) { FreePool (BufferIn); BufferIn = NULL; } if (BufferOut != NULL) { FreePool (BufferOut); BufferOut = NULL; } return Status; }