Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Siyuan Fu <siyuan.fu@intel.com> Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>
		
			
				
	
	
		
			634 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			634 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implementation of EFI TLS Protocol Interfaces.
 | 
						|
 | 
						|
  Copyright (c) 2016 - 2017, 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"
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 |