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 ); }
/** 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; }