int TlsHandleReadEvent( const fd_set *p_Set )
{
    int vl_Index;
    t_TlsConnection *p_Conn;
    int vl_Count=0;

    if( dnsResolveClient >= 0 )
    {
        // Check if there is data from DNS thread
        if( FD_ISSET(dnsResolveClient , p_Set) )
        {
            DEBUG_LOG_PRINT_LEV2(("TlsHandleReadEvent : Response to DNR query \n"));
            TlsHandleDnsResponse();
        }
    }

    for( vl_Index = 0; vl_Index < TLS_MAX_CONNECTIONS ; vl_Index++ )
    {
        p_Conn = g_TlsConnection + vl_Index;

        if( FD_ISSET(p_Conn->socket , p_Set) )
        {
            vl_Count++;
            DEBUG_LOG_PRINT_LEV2(("TlsHandleReadEvent : %d\n" , p_Conn->handle ));
            switch( p_Conn->state )
            {
            case K_TLS_STATE_HANDSHAKE_IN_PROGRESS:
                TlsDoHandshake( p_Conn );
                break;
            case K_TLS_STATE_HANDSHAKE_DONE:
            case K_TLS_STATE_SHUTDOWN_IN_PROGRESS:
                //Do a read here
                TlsDoRead(p_Conn);
                break;
            default:
                /* Not handled : K_TLS_STATE_UNUSED , K_TLS_STATE_WAIT_SERVER_CONNECTION & K_TLS_STATE_DNS_RESOLUTION_IN_PROGRESS */
                break;
            }
        }
    }

    return vl_Count;
}
e_TlsError TlsInitHandshake(t_TlsConnection *p_TlsConnection)
{
    DEBUG_LOG_PRINT_LEV2(("TlsInitHandshake : handle %d : Entry\n" , p_TlsConnection->handle ));

    p_TlsConnection->p_BIO =
 //        BIO_new_socket(
         BIO_new_fd(
         p_TlsConnection->socket,
            BIO_NOCLOSE);

      if(p_TlsConnection->p_BIO == NULL)
      {
         DEBUG_LOG_PRINT_LEV2(("ERROR failed to create SSL BIO on socket\n" ));
         if(p_TlsConnection->socket)   close(p_TlsConnection->socket);
         return K_TLS_ERROR_BIO_INIT;
      }

    // Prepare for SSL layer
     p_TlsConnection->p_SSL = SSL_new(gp_SSL_CTX);
     if(p_TlsConnection->p_SSL == NULL)
     {
        DEBUG_LOG_PRINT_LEV2(("ERROR failed to create SSL structure for SSL connection\n" ));
        BIO_free(p_TlsConnection->p_BIO);
        p_TlsConnection->p_BIO = NULL;
        return K_TLS_ERROR_SSL_INIT;
     }

     SSL_set_bio(
        p_TlsConnection->p_SSL,
        p_TlsConnection->p_BIO,
        p_TlsConnection->p_BIO);
     SSL_set_mode(p_TlsConnection->p_SSL, SSL_MODE_AUTO_RETRY);

     TlsTransitionState(p_TlsConnection , K_TLS_STATE_HANDSHAKE_IN_PROGRESS);

     DEBUG_LOG_PRINT_LEV2(("TlsInitHandshake : Exit\n"));

     return TlsDoHandshake( p_TlsConnection );
}
Exemple #3
0
/**
  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 == TLS_CONTENT_TYPE_ALERT);

      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;
}
e_TlsError TlsDoHandshake( t_TlsConnection *p_TlsConnection)
{
    int vl_Return;
    unsigned long er;


    DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : handle %d : Entry\n" , p_TlsConnection->handle));

     vl_Return = SSL_connect(p_TlsConnection->p_SSL);
     DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : vl_Return %d \n" ,vl_Return));
     if( vl_Return <= 0 )
     {
         int vl_SslError = SSL_get_error(p_TlsConnection->p_SSL,vl_Return);
         DEBUG_LOG_PRINT_LEV2(("SSL_get_error : %d\n" , vl_SslError ));
         switch(vl_SslError)
         {
         case SSL_ERROR_WANT_READ:
            vl_Return = K_TLS_NO_ERROR;
            break;
         case SSL_ERROR_WANT_WRITE:
            vl_Return = TlsDoHandshake( p_TlsConnection );
            break;
         case SSL_ERROR_SYSCALL:
             er = ERR_get_error();
             DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : SSL_ERROR_SYSCALL %s\n" , ERR_error_string(er,NULL) ));
             if(er==0)
             {
                 if(vl_Return==0)
                 {
                     DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : SSL_ERROR_SYSCALL : EOF detected on SOCKET!"));
                 }
                 else
                 {
                     DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : SSL_ERROR_SYSCALL : error on socket %s" , strerror(errno)));
                 }
             }

             TlsConnectErr(p_TlsConnection->handle , K_TLS_ERROR_SSL_HANDSHAKE);
             vl_Return = K_TLS_ERROR_SSL_HANDSHAKE;
             TlsRemoveConnection(p_TlsConnection);
             break;
         default:
            er = ERR_get_error();
            DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : %s\n" , ERR_error_string(er,NULL) ));
            DEBUG_LOG_PRINT_LEV2(("SSL_get_error : %d\n" , vl_SslError ));
            TlsConnectErr(p_TlsConnection->handle , K_TLS_ERROR_SSL_HANDSHAKE );
            vl_Return = K_TLS_ERROR_SSL_HANDSHAKE;
            TlsRemoveConnection(p_TlsConnection);
         }
     }
     else
     {
         int ret = SSL_get_verify_result(p_TlsConnection->p_SSL);
         DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : SSL_get_verify_result : %d" , ret));
         TlsTransitionState(p_TlsConnection , K_TLS_STATE_HANDSHAKE_DONE );
         TlsConnectCnf(p_TlsConnection->handle );
         vl_Return = K_TLS_NO_ERROR;
     }

     DEBUG_LOG_PRINT_LEV2(("TlsDoHandshake : Exit\n"));
     return vl_Return;
}