X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FTlsDxe%2FTlsProtocol.c;h=ad4c922c60bd2ea5300d0084a19460da56d58c0d;hp=58a83c3ab7d5b182891ed726f714d68e81da501f;hb=7618784b85c5df91fae4c0d7a910bfb07b248caf;hpb=89f06051a5c89bcd81b1375f60bb9d1cb049c0de diff --git a/NetworkPkg/TlsDxe/TlsProtocol.c b/NetworkPkg/TlsDxe/TlsProtocol.c index 58a83c3ab7..ad4c922c60 100644 --- a/NetworkPkg/TlsDxe/TlsProtocol.c +++ b/NetworkPkg/TlsDxe/TlsProtocol.c @@ -1,632 +1,633 @@ -/** @file - Implementation of EFI TLS Protocol Interfaces. - - Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
- - 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" - -EFI_TLS_PROTOCOL mTlsProtocol = { - TlsSetSessionData, - TlsGetSessionData, - TlsBuildResponsePacket, - TlsProcessPacket -}; - -/** - Set TLS session data. - - The SetSessionData() function set data for a new TLS session. All session data should - be set before BuildResponsePacket() invoked. - - @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. - @param[in] DataType TLS session data type. - @param[in] Data Pointer to session data. - @param[in] DataSize Total size of session data. - - @retval EFI_SUCCESS The TLS session data is set successfully. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - Data is NULL. - DataSize is 0. - @retval EFI_UNSUPPORTED The DataType is unsupported. - @retval EFI_ACCESS_DENIED If the DataType is one of below: - EfiTlsClientRandom - EfiTlsServerRandom - EfiTlsKeyMaterial - @retval EFI_NOT_READY Current TLS session state is NOT - EfiTlsSessionStateNotStarted. - @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. -**/ -EFI_STATUS -EFIAPI -TlsSetSessionData ( - IN EFI_TLS_PROTOCOL *This, - IN EFI_TLS_SESSION_DATA_TYPE DataType, - IN VOID *Data, - IN UINTN DataSize - ) -{ - EFI_STATUS Status; - TLS_INSTANCE *Instance; - UINT16 *CipherId; - UINTN Index; - - EFI_TPL OldTpl; - - Status = EFI_SUCCESS; - CipherId = NULL; - - if (This == NULL || Data == NULL || DataSize == 0) { - return EFI_INVALID_PARAMETER; - } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - - Instance = TLS_INSTANCE_FROM_PROTOCOL (This); - - if (DataType != EfiTlsSessionState && Instance->TlsSessionState != EfiTlsSessionNotStarted){ - Status = EFI_NOT_READY; - goto ON_EXIT; - } - - switch (DataType) { - // - // Session Configuration - // - case EfiTlsVersion: - if (DataSize != sizeof (EFI_TLS_VERSION)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - Status = TlsSetVersion (Instance->TlsConn, ((EFI_TLS_VERSION *) Data)->Major, ((EFI_TLS_VERSION *) Data)->Minor); - break; - case EfiTlsConnectionEnd: - if (DataSize != sizeof (EFI_TLS_CONNECTION_END)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - Status = TlsSetConnectionEnd (Instance->TlsConn, *((EFI_TLS_CONNECTION_END *) Data)); - break; - case EfiTlsCipherList: - CipherId = AllocatePool (DataSize); - if (CipherId == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - for (Index = 0; Index < DataSize / sizeof (EFI_TLS_CIPHER); Index++) { - *(CipherId +Index) = HTONS (*(((UINT16 *) Data) + Index)); - } - - Status = TlsSetCipherList (Instance->TlsConn, CipherId, DataSize / sizeof (EFI_TLS_CIPHER)); - - FreePool (CipherId); - break; - case EfiTlsCompressionMethod: - // - // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the - // record protocol will not be compressed. - // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html - // The TLS RFC does however not specify compression methods or their corresponding identifiers, - // so there is currently no compatible way to integrate compression with unknown peers. - // It is therefore currently not recommended to integrate compression into applications. - // Applications for non-public use may agree on certain compression methods. - // Using different compression methods with the same identifier will lead to connection failure. - // - for (Index = 0; Index < DataSize / sizeof (EFI_TLS_COMPRESSION); Index++) { - Status = TlsSetCompressionMethod (*((UINT8 *) Data + Index)); - if (EFI_ERROR (Status)) { - break; - } - } - - break; - case EfiTlsExtensionData: - Status = EFI_UNSUPPORTED; - goto ON_EXIT; - case EfiTlsVerifyMethod: - if (DataSize != sizeof (EFI_TLS_VERIFY)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - TlsSetVerify (Instance->TlsConn, *((UINT32 *) Data)); - break; - case EfiTlsSessionID: - if (DataSize != sizeof (EFI_TLS_SESSION_ID)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - Status = TlsSetSessionId ( - Instance->TlsConn, - ((EFI_TLS_SESSION_ID *) Data)->Data, - ((EFI_TLS_SESSION_ID *) Data)->Length - ); - break; - case EfiTlsSessionState: - if (DataSize != sizeof (EFI_TLS_SESSION_STATE)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; - } - - Instance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) Data; - break; - // - // Session information - // - case EfiTlsClientRandom: - Status = EFI_ACCESS_DENIED; - break; - case EfiTlsServerRandom: - Status = EFI_ACCESS_DENIED; - break; - case EfiTlsKeyMaterial: - Status = EFI_ACCESS_DENIED; - break; - // - // Unsupported type. - // - default: - Status = EFI_UNSUPPORTED; - } - -ON_EXIT: - gBS->RestoreTPL (OldTpl); - return Status; -} - -/** - Get TLS session data. - - The GetSessionData() function return the TLS session information. - - @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. - @param[in] DataType TLS session data type. - @param[in, out] Data Pointer to session data. - @param[in, out] DataSize Total size of session data. On input, it means - the size of Data buffer. On output, it means the size - of copied Data buffer if EFI_SUCCESS, and means the - size of desired Data buffer if EFI_BUFFER_TOO_SMALL. - - @retval EFI_SUCCESS The TLS session data is got successfully. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - DataSize is NULL. - Data is NULL if *DataSize is not zero. - @retval EFI_UNSUPPORTED The DataType is unsupported. - @retval EFI_NOT_FOUND The TLS session data is not found. - @retval EFI_NOT_READY The DataType is not ready in current session state. - @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data. -**/ -EFI_STATUS -EFIAPI -TlsGetSessionData ( - IN EFI_TLS_PROTOCOL *This, - IN EFI_TLS_SESSION_DATA_TYPE DataType, - IN OUT VOID *Data, OPTIONAL - IN OUT UINTN *DataSize - ) -{ - EFI_STATUS Status; - TLS_INSTANCE *Instance; - - EFI_TPL OldTpl; - - Status = EFI_SUCCESS; - - if (This == NULL || DataSize == NULL || (Data == NULL && *DataSize != 0)) { - return EFI_INVALID_PARAMETER; - } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - - Instance = TLS_INSTANCE_FROM_PROTOCOL (This); - - if (Instance->TlsSessionState == EfiTlsSessionNotStarted && - (DataType == EfiTlsSessionID || DataType == EfiTlsClientRandom || - DataType == EfiTlsServerRandom || DataType == EfiTlsKeyMaterial)) { - Status = EFI_NOT_READY; - goto ON_EXIT; - } - - switch (DataType) { - case EfiTlsVersion: - if (*DataSize < sizeof (EFI_TLS_VERSION)) { - *DataSize = sizeof (EFI_TLS_VERSION); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_VERSION); - *((UINT16 *) Data) = HTONS (TlsGetVersion (Instance->TlsConn)); - break; - case EfiTlsConnectionEnd: - if (*DataSize < sizeof (EFI_TLS_CONNECTION_END)) { - *DataSize = sizeof (EFI_TLS_CONNECTION_END); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_CONNECTION_END); - *((UINT8 *) Data) = TlsGetConnectionEnd (Instance->TlsConn); - break; - case EfiTlsCipherList: - // - // Get the current session cipher suite. - // - if (*DataSize < sizeof (EFI_TLS_CIPHER)) { - *DataSize = sizeof (EFI_TLS_CIPHER); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof(EFI_TLS_CIPHER); - Status = TlsGetCurrentCipher (Instance->TlsConn, (UINT16 *) Data); - *((UINT16 *) Data) = HTONS (*((UINT16 *) Data)); - break; - case EfiTlsCompressionMethod: - // - // Get the current session compression method. - // - if (*DataSize < sizeof (EFI_TLS_COMPRESSION)) { - *DataSize = sizeof (EFI_TLS_COMPRESSION); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_COMPRESSION); - Status = TlsGetCurrentCompressionId (Instance->TlsConn, (UINT8 *) Data); - break; - case EfiTlsExtensionData: - Status = EFI_UNSUPPORTED; - goto ON_EXIT; - case EfiTlsVerifyMethod: - if (*DataSize < sizeof (EFI_TLS_VERIFY)) { - *DataSize = sizeof (EFI_TLS_VERIFY); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_VERIFY); - *((UINT32 *) Data) = TlsGetVerify (Instance->TlsConn); - break; - case EfiTlsSessionID: - if (*DataSize < sizeof (EFI_TLS_SESSION_ID)) { - *DataSize = sizeof (EFI_TLS_SESSION_ID); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_SESSION_ID); - Status = TlsGetSessionId ( - Instance->TlsConn, - ((EFI_TLS_SESSION_ID *) Data)->Data, - &(((EFI_TLS_SESSION_ID *) Data)->Length) - ); - break; - case EfiTlsSessionState: - if (*DataSize < sizeof (EFI_TLS_SESSION_STATE)) { - *DataSize = sizeof (EFI_TLS_SESSION_STATE); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_SESSION_STATE); - CopyMem (Data, &Instance->TlsSessionState, *DataSize); - break; - case EfiTlsClientRandom: - if (*DataSize < sizeof (EFI_TLS_RANDOM)) { - *DataSize = sizeof (EFI_TLS_RANDOM); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_RANDOM); - TlsGetClientRandom (Instance->TlsConn, (UINT8 *) Data); - break; - case EfiTlsServerRandom: - if (*DataSize < sizeof (EFI_TLS_RANDOM)) { - *DataSize = sizeof (EFI_TLS_RANDOM); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_RANDOM); - TlsGetServerRandom (Instance->TlsConn, (UINT8 *) Data); - break; - case EfiTlsKeyMaterial: - if (*DataSize < sizeof (EFI_TLS_MASTER_SECRET)) { - *DataSize = sizeof (EFI_TLS_MASTER_SECRET); - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - *DataSize = sizeof (EFI_TLS_MASTER_SECRET); - Status = TlsGetKeyMaterial (Instance->TlsConn, (UINT8 *) Data); - break; - // - // Unsupported type. - // - default: - Status = EFI_UNSUPPORTED; - } - -ON_EXIT: - gBS->RestoreTPL (OldTpl); - return Status; -} - -/** - Build response packet according to TLS state machine. This function is only valid for - alert, handshake and change_cipher_spec content type. - - The BuildResponsePacket() function builds TLS response packet in response to the TLS - request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and - RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session - will be initiated and the response packet needs to be ClientHello. If RequestBuffer is - NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS - session will be closed and response packet needs to be CloseNotify. If RequestBuffer is - NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS - session has errors and the response packet needs to be Alert message based on error - type. - - @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. - @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL - means TLS need initiate the TLS session and response - packet need to be ClientHello. - @param[in] RequestSize Packet size in bytes for the most recently received TLS - packet. 0 is only valid when RequestBuffer is NULL. - @param[out] Buffer Pointer to the buffer to hold the built packet. - @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is - the buffer size provided by the caller. On output, it - is the buffer size in fact needed to contain the - packet. - - @retval EFI_SUCCESS The required TLS packet is built successfully. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - RequestBuffer is NULL but RequestSize is NOT 0. - RequestSize is 0 but RequestBuffer is NOT NULL. - BufferSize is NULL. - Buffer is NULL if *BufferSize is not zero. - @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet. - @retval EFI_NOT_READY Current TLS session state is NOT ready to build - ResponsePacket. - @retval EFI_ABORTED Something wrong build response packet. -**/ -EFI_STATUS -EFIAPI -TlsBuildResponsePacket ( - IN EFI_TLS_PROTOCOL *This, - IN UINT8 *RequestBuffer, OPTIONAL - IN UINTN RequestSize, OPTIONAL - OUT UINT8 *Buffer, OPTIONAL - IN OUT UINTN *BufferSize - ) -{ - EFI_STATUS Status; - TLS_INSTANCE *Instance; - EFI_TPL OldTpl; - - Status = EFI_SUCCESS; - - if ((This == NULL) || (BufferSize == NULL) || - (RequestBuffer == NULL && RequestSize != 0) || - (RequestBuffer != NULL && RequestSize == 0) || - (Buffer == NULL && *BufferSize !=0)) { - return EFI_INVALID_PARAMETER; - } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - - Instance = TLS_INSTANCE_FROM_PROTOCOL (This); - - if(RequestBuffer == NULL && RequestSize == 0) { - switch (Instance->TlsSessionState) { - case EfiTlsSessionNotStarted: - // - // ClientHello. - // - Status = TlsDoHandshake ( - Instance->TlsConn, - NULL, - 0, - Buffer, - BufferSize - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - // - // *BufferSize should not be zero when ClientHello. - // - if (*BufferSize == 0) { - Status = EFI_ABORTED; - goto ON_EXIT; - } - - Instance->TlsSessionState = EfiTlsSessionHandShaking; - - break; - case EfiTlsSessionClosing: - // - // TLS session will be closed and response packet needs to be CloseNotify. - // - Status = TlsCloseNotify ( - Instance->TlsConn, - Buffer, - BufferSize - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - // - // *BufferSize should not be zero when build CloseNotify message. - // - if (*BufferSize == 0) { - Status = EFI_ABORTED; - goto ON_EXIT; - } - - break; - case EfiTlsSessionError: - // - // TLS session has errors and the response packet needs to be Alert - // message based on error type. - // - Status = TlsHandleAlert ( - Instance->TlsConn, - NULL, - 0, - Buffer, - BufferSize - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - break; - default: - // - // Current TLS session state is NOT ready to build ResponsePacket. - // - Status = EFI_NOT_READY; - } - } else { - // - // 1. Received packet may have multiple TLS record messages. - // 2. One TLS record message may have multiple handshake protocol. - // 3. Some errors may be happened in handshake. - // TlsDoHandshake() can handle all of those cases. - // - if (TlsInHandshake (Instance->TlsConn)) { - Status = TlsDoHandshake ( - Instance->TlsConn, - RequestBuffer, - RequestSize, - Buffer, - BufferSize - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - if (!TlsInHandshake (Instance->TlsConn)) { - Instance->TlsSessionState = EfiTlsSessionDataTransferring; - } - } else { - // - // Must be alert message, Decrypt it and build the ResponsePacket. - // - ASSERT (((TLS_RECORD_HEADER *) RequestBuffer)->ContentType == TlsContentTypeAlert); - - Status = TlsHandleAlert ( - Instance->TlsConn, - RequestBuffer, - RequestSize, - Buffer, - BufferSize - ); - if (EFI_ERROR (Status)) { - if (Status != EFI_BUFFER_TOO_SMALL) { - Instance->TlsSessionState = EfiTlsSessionError; - } - - goto ON_EXIT; - } - } - } - -ON_EXIT: - gBS->RestoreTPL (OldTpl); - return Status; -} - -/** - Decrypt or encrypt TLS packet during session. This function is only valid after - session connected and for application_data content type. - - The ProcessPacket () function process each inbound or outbound TLS APP packet. - - @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. - @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take - responsible to handle the original FragmentTable while - it may be reallocated in TLS driver. If CryptMode is - EfiTlsEncrypt, on input these fragments contain the TLS - header and plain text TLS APP payload; on output these - fragments contain the TLS header and cipher text TLS - APP payload. If CryptMode is EfiTlsDecrypt, on input - these fragments contain the TLS header and cipher text - TLS APP payload; on output these fragments contain the - TLS header and plain text TLS APP payload. - @param[in] FragmentCount Number of fragment. - @param[in] CryptMode Crypt mode. - - @retval EFI_SUCCESS The operation completed successfully. - @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: - This is NULL. - FragmentTable is NULL. - FragmentCount is NULL. - CryptoMode is invalid. - @retval EFI_NOT_READY Current TLS session state is NOT - EfiTlsSessionDataTransferring. - @retval EFI_ABORTED Something wrong decryption the message. TLS session - status will become EfiTlsSessionError. The caller need - call BuildResponsePacket() to generate Error Alert - message and send it out. - @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation. -**/ -EFI_STATUS -EFIAPI -TlsProcessPacket ( - IN EFI_TLS_PROTOCOL *This, - IN OUT EFI_TLS_FRAGMENT_DATA **FragmentTable, - IN UINT32 *FragmentCount, - IN EFI_TLS_CRYPT_MODE CryptMode - ) -{ - EFI_STATUS Status; - TLS_INSTANCE *Instance; - - EFI_TPL OldTpl; - - Status = EFI_SUCCESS; - - if (This == NULL || FragmentTable == NULL || FragmentCount == NULL) { - return EFI_INVALID_PARAMETER; - } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - - Instance = TLS_INSTANCE_FROM_PROTOCOL (This); - - if (Instance->TlsSessionState != EfiTlsSessionDataTransferring) { - Status = EFI_NOT_READY; - goto ON_EXIT; - } - - // - // Packet sent or received may have multiple TLS record messages (Application data type). - // So,on input these fragments contain the TLS header and TLS APP payload; - // on output these fragments also contain the TLS header and TLS APP payload. - // - switch (CryptMode) { - case EfiTlsEncrypt: - Status = TlsEncryptPacket (Instance, FragmentTable, FragmentCount); - break; - case EfiTlsDecrypt: - Status = TlsDecryptPacket (Instance, FragmentTable, FragmentCount); - break; - default: - return EFI_INVALID_PARAMETER; - } - -ON_EXIT: - gBS->RestoreTPL (OldTpl); - return Status; -} +/** @file + Implementation of EFI TLS Protocol Interfaces. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+ + 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" + +EFI_TLS_PROTOCOL mTlsProtocol = { + TlsSetSessionData, + TlsGetSessionData, + TlsBuildResponsePacket, + TlsProcessPacket +}; + +/** + Set TLS session data. + + The SetSessionData() function set data for a new TLS session. All session data should + be set before BuildResponsePacket() invoked. + + @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. + @param[in] DataType TLS session data type. + @param[in] Data Pointer to session data. + @param[in] DataSize Total size of session data. + + @retval EFI_SUCCESS The TLS session data is set successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Data is NULL. + DataSize is 0. + @retval EFI_UNSUPPORTED The DataType is unsupported. + @retval EFI_ACCESS_DENIED If the DataType is one of below: + EfiTlsClientRandom + EfiTlsServerRandom + EfiTlsKeyMaterial + @retval EFI_NOT_READY Current TLS session state is NOT + EfiTlsSessionStateNotStarted. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. +**/ +EFI_STATUS +EFIAPI +TlsSetSessionData ( + IN EFI_TLS_PROTOCOL *This, + IN EFI_TLS_SESSION_DATA_TYPE DataType, + IN VOID *Data, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + TLS_INSTANCE *Instance; + UINT16 *CipherId; + UINTN Index; + + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + CipherId = NULL; + + if (This == NULL || Data == NULL || DataSize == 0) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = TLS_INSTANCE_FROM_PROTOCOL (This); + + if (DataType != EfiTlsSessionState && Instance->TlsSessionState != EfiTlsSessionNotStarted){ + Status = EFI_NOT_READY; + goto ON_EXIT; + } + + switch (DataType) { + // + // Session Configuration + // + case EfiTlsVersion: + if (DataSize != sizeof (EFI_TLS_VERSION)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = TlsSetVersion (Instance->TlsConn, ((EFI_TLS_VERSION *) Data)->Major, ((EFI_TLS_VERSION *) Data)->Minor); + break; + case EfiTlsConnectionEnd: + if (DataSize != sizeof (EFI_TLS_CONNECTION_END)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = TlsSetConnectionEnd (Instance->TlsConn, *((EFI_TLS_CONNECTION_END *) Data)); + break; + case EfiTlsCipherList: + CipherId = AllocatePool (DataSize); + if (CipherId == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + for (Index = 0; Index < DataSize / sizeof (EFI_TLS_CIPHER); Index++) { + *(CipherId +Index) = HTONS (*(((UINT16 *) Data) + Index)); + } + + Status = TlsSetCipherList (Instance->TlsConn, CipherId, DataSize / sizeof (EFI_TLS_CIPHER)); + + FreePool (CipherId); + break; + case EfiTlsCompressionMethod: + // + // TLS seems only define one CompressionMethod.null, which specifies that data exchanged via the + // record protocol will not be compressed. + // More information from OpenSSL: http://www.openssl.org/docs/manmaster/ssl/SSL_COMP_add_compression_method.html + // The TLS RFC does however not specify compression methods or their corresponding identifiers, + // so there is currently no compatible way to integrate compression with unknown peers. + // It is therefore currently not recommended to integrate compression into applications. + // Applications for non-public use may agree on certain compression methods. + // Using different compression methods with the same identifier will lead to connection failure. + // + for (Index = 0; Index < DataSize / sizeof (EFI_TLS_COMPRESSION); Index++) { + Status = TlsSetCompressionMethod (*((UINT8 *) Data + Index)); + if (EFI_ERROR (Status)) { + break; + } + } + + break; + case EfiTlsExtensionData: + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + case EfiTlsVerifyMethod: + if (DataSize != sizeof (EFI_TLS_VERIFY)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + TlsSetVerify (Instance->TlsConn, *((UINT32 *) Data)); + break; + case EfiTlsSessionID: + if (DataSize != sizeof (EFI_TLS_SESSION_ID)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Status = TlsSetSessionId ( + Instance->TlsConn, + ((EFI_TLS_SESSION_ID *) Data)->Data, + ((EFI_TLS_SESSION_ID *) Data)->Length + ); + break; + case EfiTlsSessionState: + if (DataSize != sizeof (EFI_TLS_SESSION_STATE)) { + Status = EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Instance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) Data; + break; + // + // Session information + // + case EfiTlsClientRandom: + Status = EFI_ACCESS_DENIED; + break; + case EfiTlsServerRandom: + Status = EFI_ACCESS_DENIED; + break; + case EfiTlsKeyMaterial: + Status = EFI_ACCESS_DENIED; + break; + // + // Unsupported type. + // + default: + Status = EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Get TLS session data. + + The GetSessionData() function return the TLS session information. + + @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. + @param[in] DataType TLS session data type. + @param[in, out] Data Pointer to session data. + @param[in, out] DataSize Total size of session data. On input, it means + the size of Data buffer. On output, it means the size + of copied Data buffer if EFI_SUCCESS, and means the + size of desired Data buffer if EFI_BUFFER_TOO_SMALL. + + @retval EFI_SUCCESS The TLS session data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + DataSize is NULL. + Data is NULL if *DataSize is not zero. + @retval EFI_UNSUPPORTED The DataType is unsupported. + @retval EFI_NOT_FOUND The TLS session data is not found. + @retval EFI_NOT_READY The DataType is not ready in current session state. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the data. +**/ +EFI_STATUS +EFIAPI +TlsGetSessionData ( + IN EFI_TLS_PROTOCOL *This, + IN EFI_TLS_SESSION_DATA_TYPE DataType, + IN OUT VOID *Data, OPTIONAL + IN OUT UINTN *DataSize + ) +{ + EFI_STATUS Status; + TLS_INSTANCE *Instance; + + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + + if (This == NULL || DataSize == NULL || (Data == NULL && *DataSize != 0)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = TLS_INSTANCE_FROM_PROTOCOL (This); + + if (Instance->TlsSessionState == EfiTlsSessionNotStarted && + (DataType == EfiTlsSessionID || DataType == EfiTlsClientRandom || + DataType == EfiTlsServerRandom || DataType == EfiTlsKeyMaterial)) { + Status = EFI_NOT_READY; + goto ON_EXIT; + } + + switch (DataType) { + case EfiTlsVersion: + if (*DataSize < sizeof (EFI_TLS_VERSION)) { + *DataSize = sizeof (EFI_TLS_VERSION); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_VERSION); + *((UINT16 *) Data) = HTONS (TlsGetVersion (Instance->TlsConn)); + break; + case EfiTlsConnectionEnd: + if (*DataSize < sizeof (EFI_TLS_CONNECTION_END)) { + *DataSize = sizeof (EFI_TLS_CONNECTION_END); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_CONNECTION_END); + *((UINT8 *) Data) = TlsGetConnectionEnd (Instance->TlsConn); + break; + case EfiTlsCipherList: + // + // Get the current session cipher suite. + // + if (*DataSize < sizeof (EFI_TLS_CIPHER)) { + *DataSize = sizeof (EFI_TLS_CIPHER); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof(EFI_TLS_CIPHER); + Status = TlsGetCurrentCipher (Instance->TlsConn, (UINT16 *) Data); + *((UINT16 *) Data) = HTONS (*((UINT16 *) Data)); + break; + case EfiTlsCompressionMethod: + // + // Get the current session compression method. + // + if (*DataSize < sizeof (EFI_TLS_COMPRESSION)) { + *DataSize = sizeof (EFI_TLS_COMPRESSION); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_COMPRESSION); + Status = TlsGetCurrentCompressionId (Instance->TlsConn, (UINT8 *) Data); + break; + case EfiTlsExtensionData: + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + case EfiTlsVerifyMethod: + if (*DataSize < sizeof (EFI_TLS_VERIFY)) { + *DataSize = sizeof (EFI_TLS_VERIFY); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_VERIFY); + *((UINT32 *) Data) = TlsGetVerify (Instance->TlsConn); + break; + case EfiTlsSessionID: + if (*DataSize < sizeof (EFI_TLS_SESSION_ID)) { + *DataSize = sizeof (EFI_TLS_SESSION_ID); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_SESSION_ID); + Status = TlsGetSessionId ( + Instance->TlsConn, + ((EFI_TLS_SESSION_ID *) Data)->Data, + &(((EFI_TLS_SESSION_ID *) Data)->Length) + ); + break; + case EfiTlsSessionState: + if (*DataSize < sizeof (EFI_TLS_SESSION_STATE)) { + *DataSize = sizeof (EFI_TLS_SESSION_STATE); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_SESSION_STATE); + CopyMem (Data, &Instance->TlsSessionState, *DataSize); + break; + case EfiTlsClientRandom: + if (*DataSize < sizeof (EFI_TLS_RANDOM)) { + *DataSize = sizeof (EFI_TLS_RANDOM); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_RANDOM); + TlsGetClientRandom (Instance->TlsConn, (UINT8 *) Data); + break; + case EfiTlsServerRandom: + if (*DataSize < sizeof (EFI_TLS_RANDOM)) { + *DataSize = sizeof (EFI_TLS_RANDOM); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_RANDOM); + TlsGetServerRandom (Instance->TlsConn, (UINT8 *) Data); + break; + case EfiTlsKeyMaterial: + if (*DataSize < sizeof (EFI_TLS_MASTER_SECRET)) { + *DataSize = sizeof (EFI_TLS_MASTER_SECRET); + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + *DataSize = sizeof (EFI_TLS_MASTER_SECRET); + Status = TlsGetKeyMaterial (Instance->TlsConn, (UINT8 *) Data); + break; + // + // Unsupported type. + // + default: + Status = EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Build response packet according to TLS state machine. This function is only valid for + alert, handshake and change_cipher_spec content type. + + The BuildResponsePacket() function builds TLS response packet in response to the TLS + request packet specified by RequestBuffer and RequestSize. If RequestBuffer is NULL and + RequestSize is 0, and TLS session status is EfiTlsSessionNotStarted, the TLS session + will be initiated and the response packet needs to be ClientHello. If RequestBuffer is + NULL and RequestSize is 0, and TLS session status is EfiTlsSessionClosing, the TLS + session will be closed and response packet needs to be CloseNotify. If RequestBuffer is + NULL and RequestSize is 0, and TLS session status is EfiTlsSessionError, the TLS + session has errors and the response packet needs to be Alert message based on error + type. + + @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. + @param[in] RequestBuffer Pointer to the most recently received TLS packet. NULL + means TLS need initiate the TLS session and response + packet need to be ClientHello. + @param[in] RequestSize Packet size in bytes for the most recently received TLS + packet. 0 is only valid when RequestBuffer is NULL. + @param[out] Buffer Pointer to the buffer to hold the built packet. + @param[in, out] BufferSize Pointer to the buffer size in bytes. On input, it is + the buffer size provided by the caller. On output, it + is the buffer size in fact needed to contain the + packet. + + @retval EFI_SUCCESS The required TLS packet is built successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + RequestBuffer is NULL but RequestSize is NOT 0. + RequestSize is 0 but RequestBuffer is NOT NULL. + BufferSize is NULL. + Buffer is NULL if *BufferSize is not zero. + @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to hold the response packet. + @retval EFI_NOT_READY Current TLS session state is NOT ready to build + ResponsePacket. + @retval EFI_ABORTED Something wrong build response packet. +**/ +EFI_STATUS +EFIAPI +TlsBuildResponsePacket ( + IN EFI_TLS_PROTOCOL *This, + IN UINT8 *RequestBuffer, OPTIONAL + IN UINTN RequestSize, OPTIONAL + OUT UINT8 *Buffer, OPTIONAL + IN OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + TLS_INSTANCE *Instance; + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + + if ((This == NULL) || (BufferSize == NULL) || + (RequestBuffer == NULL && RequestSize != 0) || + (RequestBuffer != NULL && RequestSize == 0) || + (Buffer == NULL && *BufferSize !=0)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = TLS_INSTANCE_FROM_PROTOCOL (This); + + if(RequestBuffer == NULL && RequestSize == 0) { + switch (Instance->TlsSessionState) { + case EfiTlsSessionNotStarted: + // + // ClientHello. + // + Status = TlsDoHandshake ( + Instance->TlsConn, + NULL, + 0, + Buffer, + BufferSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // *BufferSize should not be zero when ClientHello. + // + if (*BufferSize == 0) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + + Instance->TlsSessionState = EfiTlsSessionHandShaking; + + break; + case EfiTlsSessionClosing: + // + // TLS session will be closed and response packet needs to be CloseNotify. + // + Status = TlsCloseNotify ( + Instance->TlsConn, + Buffer, + BufferSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // *BufferSize should not be zero when build CloseNotify message. + // + if (*BufferSize == 0) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + + break; + case EfiTlsSessionError: + // + // TLS session has errors and the response packet needs to be Alert + // message based on error type. + // + Status = TlsHandleAlert ( + Instance->TlsConn, + NULL, + 0, + Buffer, + BufferSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + break; + default: + // + // Current TLS session state is NOT ready to build ResponsePacket. + // + Status = EFI_NOT_READY; + } + } else { + // + // 1. Received packet may have multiple TLS record messages. + // 2. One TLS record message may have multiple handshake protocol. + // 3. Some errors may be happened in handshake. + // TlsDoHandshake() can handle all of those cases. + // + if (TlsInHandshake (Instance->TlsConn)) { + Status = TlsDoHandshake ( + Instance->TlsConn, + RequestBuffer, + RequestSize, + Buffer, + BufferSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (!TlsInHandshake (Instance->TlsConn)) { + Instance->TlsSessionState = EfiTlsSessionDataTransferring; + } + } else { + // + // Must be alert message, Decrypt it and build the ResponsePacket. + // + ASSERT (((TLS_RECORD_HEADER *) RequestBuffer)->ContentType == TlsContentTypeAlert); + + Status = TlsHandleAlert ( + Instance->TlsConn, + RequestBuffer, + RequestSize, + Buffer, + BufferSize + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_BUFFER_TOO_SMALL) { + Instance->TlsSessionState = EfiTlsSessionError; + } + + goto ON_EXIT; + } + } + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Decrypt or encrypt TLS packet during session. This function is only valid after + session connected and for application_data content type. + + The ProcessPacket () function process each inbound or outbound TLS APP packet. + + @param[in] This Pointer to the EFI_TLS_PROTOCOL instance. + @param[in, out] FragmentTable Pointer to a list of fragment. The caller will take + responsible to handle the original FragmentTable while + it may be reallocated in TLS driver. If CryptMode is + EfiTlsEncrypt, on input these fragments contain the TLS + header and plain text TLS APP payload; on output these + fragments contain the TLS header and cipher text TLS + APP payload. If CryptMode is EfiTlsDecrypt, on input + these fragments contain the TLS header and cipher text + TLS APP payload; on output these fragments contain the + TLS header and plain text TLS APP payload. + @param[in] FragmentCount Number of fragment. + @param[in] CryptMode Crypt mode. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + FragmentTable is NULL. + FragmentCount is NULL. + CryptoMode is invalid. + @retval EFI_NOT_READY Current TLS session state is NOT + EfiTlsSessionDataTransferring. + @retval EFI_ABORTED Something wrong decryption the message. TLS session + status will become EfiTlsSessionError. The caller need + call BuildResponsePacket() to generate Error Alert + message and send it out. + @retval EFI_OUT_OF_RESOURCES No enough resource to finish the operation. +**/ +EFI_STATUS +EFIAPI +TlsProcessPacket ( + IN EFI_TLS_PROTOCOL *This, + IN OUT EFI_TLS_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN EFI_TLS_CRYPT_MODE CryptMode + ) +{ + EFI_STATUS Status; + TLS_INSTANCE *Instance; + + EFI_TPL OldTpl; + + Status = EFI_SUCCESS; + + if (This == NULL || FragmentTable == NULL || FragmentCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + Instance = TLS_INSTANCE_FROM_PROTOCOL (This); + + if (Instance->TlsSessionState != EfiTlsSessionDataTransferring) { + Status = EFI_NOT_READY; + goto ON_EXIT; + } + + // + // Packet sent or received may have multiple TLS record messages (Application data type). + // So,on input these fragments contain the TLS header and TLS APP payload; + // on output these fragments also contain the TLS header and TLS APP payload. + // + switch (CryptMode) { + case EfiTlsEncrypt: + Status = TlsEncryptPacket (Instance, FragmentTable, FragmentCount); + break; + case EfiTlsDecrypt: + Status = TlsDecryptPacket (Instance, FragmentTable, FragmentCount); + break; + default: + return EFI_INVALID_PARAMETER; + } + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} +