Fork me on GitHub

State machine outlook v0.2

Haka can analyze states of a network protocol with its state machine. A state machine is defined as a set of states and a set of transition functions between these states. This post will present a part of the SSL state machine we used in the previous blog post to detect heartbleed.

SSL State machine

The RFC 6101 specifies the state machine for SSL protocol. In this post we use a simpler version, defined as:

ssl_states

In the following, we present the main steps towards the specification of SSL state machine with Haka.

Creating a state machine

A single line creates the state machine

ssl_dissector.states = haka.state_machine.new("ssl", function ()
    state_type(BidirectionalState)

    (...)
end)

We also select which state type we want to use, in our case it is a basic bidectional state which allow to make the difference between client to server communication and server to client.

Defining new states

New states are created by defining a name, and transitions. Transitions can be seen as path from a state to another state.

We create a first state, called hello_request and three transitions:

hello_request = state(ssl_dissector.grammar.sslv3_client_hello, nil)

hello_request:on{
    event = events.fail,
    execute = function (self)
        self:drop()
    end
}

hello_request:on{
	event = events.parse_error,
	jump = fail
}

hello_request{
	event = events.up,
	jump = client_hello_done
}

The state is created based on the grammar element sslv3_client_hello. The second parameter is nil as this state does not expect any data from the server.

The transitions we used in the ssl dissector from a Client Hello are the following:

  • The first one, fail is a convenient transition to call in case of any error. As its name suggests, the drop() function drops the connection which is a reasonable default action.
  • The second one, parse_error is called when data received cannot be correctly parsed by the grammar associated to the state. In which case we will jump to a pseudo-state named fail.
  • The last transition, up is called when data is received from the client to the server. The parsing has verified the data and we can jump to the state client_hello_done.

The next steps to write the SSL state machine are writing the client_hello_done state and its transitions to another states and so on.

Creating events

Haka dissector can register events which are later used in security rules. In order to be used, events have to be registered, then triggered with optional parameters. In this example, we show how to trigger an event inside the state machine.

Registering events

Registering event is made by the register_event function which takes a name as parameter:

ssl_dissector:register_event('client_hello')

Triggering events

Triggering an event is done with the trigger() function. In the following example, we trigger an event whenever a Client Hello record is received which enables the evaluation of all security rules registered on that particular event:

hello_request{
    event = events.up,
    execute = function (self, res)
        self:trigger('client_hello', res)
    end,
    jump = client_hello_done
}

Conclusion

State machine is a powerful, yet simple, way to follow network protocol states. Events are the glue between network flows and security rules. You can read modules/protocol/tcp/tcp_connection.lua in develop branch for a preview of a more complex state machine description which manages tcp transitions.

Full explanation of Haka state machine will be provided in the release 0.2 with tutorials.