REF: https://bugzilla.tianocore.org/show_bug.cgi?id=960 CVE: CVE-2019-14553 The new data type named "EfiTlsVerifyHost" and the EFI_TLS_VERIFY_HOST_FLAG are supported in TLS protocol. Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Long Qin <qin.long@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Acked-by: Laszlo Ersek <lersek@redhat.com> Message-Id: <20190927034441.3096-4-Jiaxin.wu@intel.com> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Jiaxin Wu <jiaxin.wu@intel.com> Cc: Sivaraman Nainar <sivaramann@amiindia.co.in> Cc: Xiaoyu Lu <xiaoyux.lu@intel.com> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			677 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			677 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation of EFI TLS Protocol Interfaces.
 | |
| 
 | |
|   Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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.
 | |
|                                   DataSize is invalid for DataType.
 | |
|   @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;
 | |
|   CONST EFI_TLS_CIPHER      *TlsCipherList;
 | |
|   UINTN                     CipherCount;
 | |
|   CONST EFI_TLS_VERIFY_HOST *TlsVerifyHost;
 | |
|   EFI_TLS_VERIFY            VerifyMethod;
 | |
|   UINTN                     VerifyMethodSize;
 | |
|   UINTN                     Index;
 | |
| 
 | |
|   EFI_TPL                   OldTpl;
 | |
| 
 | |
|   Status           = EFI_SUCCESS;
 | |
|   CipherId         = NULL;
 | |
|   VerifyMethodSize = sizeof (EFI_TLS_VERIFY);
 | |
| 
 | |
|   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:
 | |
|     if (DataSize % sizeof (EFI_TLS_CIPHER) != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     CipherId = AllocatePool (DataSize);
 | |
|     if (CipherId == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     TlsCipherList = (CONST EFI_TLS_CIPHER *) Data;
 | |
|     CipherCount = DataSize / sizeof (EFI_TLS_CIPHER);
 | |
|     for (Index = 0; Index < CipherCount; Index++) {
 | |
|       CipherId[Index] = ((TlsCipherList[Index].Data1 << 8) |
 | |
|                          TlsCipherList[Index].Data2);
 | |
|     }
 | |
| 
 | |
|     Status = TlsSetCipherList (Instance->TlsConn, CipherId, CipherCount);
 | |
| 
 | |
|     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 EfiTlsVerifyHost:
 | |
|     if (DataSize != sizeof (EFI_TLS_VERIFY_HOST)) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     TlsVerifyHost = (CONST EFI_TLS_VERIFY_HOST *) Data;
 | |
| 
 | |
|     if ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_ALWAYS_CHECK_SUBJECT) != 0 &&
 | |
|         (TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NEVER_CHECK_SUBJECT) != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     if ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NO_WILDCARDS) != 0 &&
 | |
|         ((TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS) != 0 ||
 | |
|          (TlsVerifyHost->Flags & EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS) != 0)) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Status = This->GetSessionData (This, EfiTlsVerifyMethod, &VerifyMethod, &VerifyMethodSize);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     if ((VerifyMethod & EFI_TLS_VERIFY_PEER) == 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Status = TlsSetVerifyHost (Instance->TlsConn, TlsVerifyHost->Flags, TlsVerifyHost->HostName);
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 |