Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/pico/fsmpico.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,14 @@ FsmPico * fsmpico_new();
void fsmpico_delete(FsmPico * fsmpico);
void fsmpico_set_functions(FsmPico * fsmpico, FsmWrite write, FsmSetTimeout setTimeout, FsmError error, FsmReconnect reconnect, FsmDisconnect disconnect, FsmAuthenticated authenticated, FsmSessionEnded sessionEnded, FsmStatusUpdate statusUpdate);
void fsmpico_set_userdata(FsmPico * fsmpico, void * user_data);
Buffer const * fsmpico_get_received_extra_data(FsmPico * fsmpico);
void fsmpico_set_outbound_extra_data(FsmPico * fsmpico, Buffer const * extraData);

// Use these functions to control the authentication process
void fsmpico_start(FsmPico * fsmpico, Buffer const * extraData, EC_KEY * serviceIdPubKey, EC_KEY * clientIdPubKey, EVP_PKEY * clientIdPrivKey);
void fsmpico_stop(FsmPico * fsmpico);
FSMPICOSTATE fsmpico_get_state(FsmPico * fsmpico);
void fsmpico_send_extra_data(FsmPico * fsmpico);

// Call these functions when an event occurs
void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length);
Expand Down
1 change: 1 addition & 0 deletions include/pico/fsmservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ DLL_PUBLIC void fsmservice_set_outbound_extra_data(FsmService * fsmservice, Buff
DLL_PUBLIC void fsmservice_start(FsmService * fsmservice, Shared * shared, Users const * users, Buffer const * extraData);
DLL_PUBLIC void fsmservice_stop(FsmService * fsmservice);
DLL_PUBLIC FSMSERVICESTATE fsmservice_get_state(FsmService * fsmservice);
DLL_PUBLIC void fsmservice_send_extra_data(FsmService * fsmpico);

// Call these functions when an event occurs
DLL_PUBLIC void fsmservice_read(FsmService * fsmservice, char const * data, size_t length);
Expand Down
2 changes: 2 additions & 0 deletions include/pico/messageservicereauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ typedef struct _MessageServiceReAuth MessageServiceReAuth;
MessageServiceReAuth * messageservicereauth_new();
void messageservicereauth_delete(MessageServiceReAuth * messageservicereauth);
void messageservicereauth_set(MessageServiceReAuth * messageservicereauth, Buffer * sharedKey, long int timeout, REAUTHSTATE reauthState, SequenceNumber const * sequenceNum);
void messageservicereauth_set_extra_data(MessageServiceReAuth * messageservicereauth, const Buffer * extraData);
const Buffer * messageservicereauth_get_extra_data(MessageServiceReAuth * messageservicereauth);
void messageservicereauth_serialize(MessageServiceReAuth * messageservicereauth, Buffer * buffer);
bool messageservicereauth_deserialize(MessageServiceReAuth * messageservicereauth, Buffer const * buffer);
int messageservicereauth_get_timeout(MessageServiceReAuth * messageservicereauth);
Expand Down
170 changes: 145 additions & 25 deletions src/fsmpico.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@

// Defines

#define READ_TIMEOUT (5000)
#define CONTINUOUS_TIMEOUT_LEEWAY (1000)
#define RECONNECT_DELAY (10000)
#define CONTAUTH_LEEWAY (1000)
#define MAX(x,y) ((x) > (y) ? (x) : (y))
Expand Down Expand Up @@ -125,10 +127,13 @@ struct _FsmPico {
Buffer * sharedKey;
Shared * shared;
Buffer * extraData;
Buffer * returnedExtraData;

FSMPICOSTATE state;
AuthFsmComms * comms;
void * user_data;

int reauthDelay;
};

// Function prototypes
Expand All @@ -138,7 +143,7 @@ static bool readMessageServiceAuth(FsmPico * fsmpico, Buffer const * message);
static void createMessagePicoAuth(FsmPico * fsmpico, Buffer * message, Buffer const * sendExtraData);
static bool readMessageStatus(FsmPico * fsmpico, Buffer const * message, Buffer * returnedExtraData, char *status);
static void createMessagePicoReauth(FsmPico * fsmpico, Buffer * message, Buffer const * sendExtraData);
static bool readMessageServiceReauth(FsmPico * fsmpico, Buffer const * message, int * timeout);
static bool readMessageServiceReauth(FsmPico * fsmpico, Buffer const * message, int * timeout, Buffer * returnedExtraData);
static void stateTransition(FsmPico* fsmpico, FSMPICOSTATE newState);

static void FsmWriteNull(char const * data, size_t length, void * user_data);
Expand All @@ -164,6 +169,7 @@ FsmPico * fsmpico_new() {

fsmpico->shared = shared_new();
fsmpico->extraData = buffer_new(0);
fsmpico->returnedExtraData = buffer_new(0);

fsmpico->currentState = REAUTHSTATE_INVALID;
fsmpico->picoSeqNumber = sequencenumber_new();
Expand All @@ -183,6 +189,8 @@ FsmPico * fsmpico_new() {
fsmpico->comms->sessionEnded = FsmSessionEndedNull;
fsmpico->comms->statusUpdate = FsmStatusUpdateNull;

fsmpico->reauthDelay = 0;

return fsmpico;
}

Expand Down Expand Up @@ -212,6 +220,9 @@ void fsmpico_delete(FsmPico * fsmpico) {
buffer_delete(fsmpico->sharedKey);
fsmpico->sharedKey = NULL;
}

buffer_delete(fsmpico->extraData);
buffer_delete(fsmpico->returnedExtraData);

FREE(fsmpico->comms);

Expand Down Expand Up @@ -362,16 +373,16 @@ void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length) {
LOG(LOG_DEBUG, "Read");

bool result;
Buffer * receivedExtraData;
int timeout;
Buffer * message;
Buffer * dataread;
Buffer * extraDataToSend;
char status;

receivedExtraData = buffer_new(0);
message = buffer_new(0);
dataread = buffer_new(length);
buffer_append(dataread, data, length);
extraDataToSend = buffer_new(0);

// TODO: If the reads fail, should move to an error state
switch (fsmpico->state) {
Expand All @@ -382,10 +393,12 @@ void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length) {
createMessagePicoAuth(fsmpico, message, fsmpico->extraData);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_STATUS);
// set a timeout for waiting for the status message
fsmpico->comms->setTimeout(READ_TIMEOUT, fsmpico->user_data);
}
break;
case FSMPICOSTATE_STATUS:
result = readMessageStatus(fsmpico, dataread, receivedExtraData, &status);
result = readMessageStatus(fsmpico, dataread, fsmpico->returnedExtraData, &status);
if (result) {
fsmpico->comms->authenticated((int) status, fsmpico->user_data);
fsmpico->comms->disconnect(fsmpico->user_data);
Expand All @@ -405,12 +418,25 @@ void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length) {
break;
case FSMPICOSTATE_CONTSTARTSERVICE:
case FSMPICOSTATE_SERVICEREAUTH:
result = readMessageServiceReauth(fsmpico, dataread, &timeout);
result = readMessageServiceReauth(fsmpico, dataread, &timeout, fsmpico->returnedExtraData);
if (result) {
stateTransition(fsmpico, FSMPICOSTATE_PICOREAUTH);
LOG(LOG_DEBUG, "Timeout set to: %d", timeout);
// Wait for timeout
fsmpico->comms->setTimeout(MAX((timeout - CONTAUTH_LEEWAY), 0), fsmpico->user_data);
fsmpico->reauthDelay = timeout;
// reply with the PicoReauth message
createMessagePicoReauth(fsmpico, message, extraDataToSend);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_SERVICEREAUTH);
// set a timeout for awaiting a response
fsmpico->comms->setTimeout(fsmpico->reauthDelay + CONTINUOUS_TIMEOUT_LEEWAY, fsmpico->user_data);
}
break;
case FSMPICOSTATE_PICOREAUTH:
result = readMessageServiceReauth(fsmpico, dataread, &timeout, fsmpico->returnedExtraData);
if (result) {
stateTransition(fsmpico, FSMPICOSTATE_PICOREAUTH);
fsmpico->reauthDelay = timeout;
// Update reauthDelay but keep the previous timeout
// TODO assert we are waiting for a timeout?
}
break;
default:
Expand All @@ -419,9 +445,9 @@ void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length) {
break;
}

buffer_delete(receivedExtraData);
buffer_delete(message);
buffer_delete(dataread);
buffer_delete(extraDataToSend);
}

/**
Expand All @@ -430,26 +456,26 @@ void fsmpico_read(FsmPico * fsmpico, char const * data, size_t length) {
* @param fsmpico The object to apply to.
*/
void fsmpico_connected(FsmPico * fsmpico) {
Buffer * extraData;
Buffer * message;

LOG(LOG_DEBUG, "Connected");

extraData = buffer_new(0);
message = buffer_new(0);

switch (fsmpico->state) {
case FSMPICOSTATE_START:
createMessageStart(fsmpico, message);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_SERVICEAUTH);
// set a timeout for waiting for the service auth message
fsmpico->comms->setTimeout(READ_TIMEOUT, fsmpico->user_data);
break;
case FSMPICOSTATE_CONTSTARTPICO:
fsmpico->currentState = REAUTHSTATE_CONTINUE;
buffer_clear(fsmpico->sharedKey);
buffer_append_buffer(fsmpico->sharedKey, shared_get_shared_key(fsmpico->shared));
sequencenumber_random(fsmpico->picoSeqNumber);
createMessagePicoReauth(fsmpico, message, extraData);
createMessagePicoReauth(fsmpico, message, fsmpico->extraData);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_CONTSTARTSERVICE);
break;
Expand All @@ -459,7 +485,6 @@ void fsmpico_connected(FsmPico * fsmpico) {
break;
}

buffer_delete(extraData);
buffer_delete(message);
}

Expand Down Expand Up @@ -498,33 +523,121 @@ void fsmpico_disconnected(FsmPico * fsmpico) {
* @param fsmpico The object to apply to.
*/
void fsmpico_timeout(FsmPico * fsmpico) {
Buffer * extraData;
Buffer * message;

LOG(LOG_DEBUG, "Timeout");

extraData = buffer_new(0);
message = buffer_new(0);

switch (fsmpico->state) {
case FSMPICOSTATE_CONTSTARTPICO:
case FSMPICOSTATE_CONTSTARTPICO:
LOG(LOG_DEBUG, "Reconnecting for continuous authentication");
fsmpico->comms->reconnect(fsmpico->user_data);
break;
case FSMPICOSTATE_SERVICEAUTH:
case FSMPICOSTATE_STATUS:
case FSMPICOSTATE_SERVICEREAUTH:
// gave up waiting for a reply to a sent message, enter error state
stateTransition(fsmpico, FSMPICOSTATE_ERROR);
fsmpico->comms->error(fsmpico->user_data);
break;
case FSMPICOSTATE_INVALID:
case FSMPICOSTATE_ERROR:
// in these states, the state machine is stopped, so ignore it (but log)
LOG(LOG_DEBUG, "Timer fired during an invalid state");
break;
default:
// in any other state, we're not expecting a timeout and this is an error
stateTransition(fsmpico, FSMPICOSTATE_ERROR);
fsmpico->comms->error(fsmpico->user_data);
break;
}
}

/**
* Get the latest extra data that was sent by the Service. This is updated when
* the service sends either a ServiceAuth or PicoReauth message. The value is reset
* for each of these messages, and so the previous value will be wiped when
* either of these messages is received (even if the Pico doesn't send any
* extra data).
*
* To be alerted to any fresh data that arrives, the simplest approach is to
* set up an FsmStatusUpdate callback and check for any data recevied on either
* of the following two events:
*
* 1. FSMPICOSTATE_STATUS
* 2. FSMPICOSTATE_SERVICEREAUTH
*
* Then make a call using this function to check whether any new data
* has arrived (in which case, the returned buffer will be non-empty).
*
* @param fsmpico The object to get the extra data from.
* @return The latest extra data received from the Service, or an empty buffer.
*/
Buffer const * fsmpico_get_received_extra_data(FsmPico * fsmpico) {
return fsmpico->returnedExtraData;
}

/**
*
* Set the extra data that will be sent to the Service. The data is sent in the
* Status and ServiceReauth messages. As such, to ensure it's set prior to each
* of these messages being sent, it's safe to set the new extra data when an
* update notifcation is triggered for either of the following events:
*
* 1. FSMPICOSTATE_STATUS
* 2. FSMPICOSTATE_SERVICEREAUTH
*
* These two events are those that immediately proceed the arrival of a
* Status or ServiceReauth message.
*
* @param fsmpico The object to set the extra data.
* @return The next extra data to be sent to the Service.
*/
void fsmpico_set_outbound_extra_data(FsmPico * fsmpico, Buffer const * extraData) {
// Record the extra data
buffer_clear(fsmpico->extraData);
if (extraData != NULL) {
buffer_append_buffer(fsmpico->extraData, extraData);
}
}

/**
* This functions should be called after fsmpico_set_outbound_extra_data
* if the application using FsmPico wants that data to be sent immediately.
* This functions only works after continuous authentication has been
* established.
*
* @param fsmpico The object to containing the state
* @param buffer Data to be sent
*
*/
void fsmpico_send_extra_data(FsmPico* fsmpico) {
Buffer * message;

LOG(LOG_DEBUG, "fsmpico_send_extra_data");

message = buffer_new(0);

switch (fsmpico->state) {
case FSMPICOSTATE_PICOREAUTH:
createMessagePicoReauth(fsmpico, message, extraData);
createMessagePicoReauth(fsmpico, message, fsmpico->extraData);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_SERVICEREAUTH);
// set a timeout for awaiting a response
fsmpico->comms->setTimeout(fsmpico->reauthDelay + CONTINUOUS_TIMEOUT_LEEWAY, fsmpico->user_data);
break;
case FSMPICOSTATE_SERVICEREAUTH:
createMessagePicoReauth(fsmpico, message, fsmpico->extraData);
fsmpico->comms->write(buffer_get_buffer(message), buffer_get_pos(message), fsmpico->user_data);
stateTransition(fsmpico, FSMPICOSTATE_SERVICEREAUTH);
// Keep the previous timeout waiting for service
// TODO assert we are waiting for a timeout?
break;
default:
LOG(LOG_DEBUG, "Timer fired during an invalid state");
LOG(LOG_DEBUG, "Sending data during an invalid state");
break;
}

buffer_delete(extraData);
buffer_delete(message);
}

}

void stateTransition(FsmPico* fsmpico, FSMPICOSTATE newState) {
fsmpico->state = newState;
Expand Down Expand Up @@ -655,8 +768,10 @@ static void createMessagePicoReauth(FsmPico * fsmpico, Buffer * message, Buffer
* @param fsmpico The object to apply to.
* @param message The message data to interpret.
* @param timeout A pointer to an integer to return the timeout value in.
* @param returnedExtraData A buffer to store any extra data that was extracted
* from the message.
*/
static bool readMessageServiceReauth(FsmPico * fsmpico, Buffer const * message, int * timeout) {
static bool readMessageServiceReauth(FsmPico * fsmpico, Buffer const * message, int * timeout, Buffer * returnedExtraData) {
MessageServiceReAuth * messageservicereauth;
bool result;
bool sequencenumber_match;
Expand Down Expand Up @@ -689,6 +804,11 @@ static bool readMessageServiceReauth(FsmPico * fsmpico, Buffer const * message,
}
}

if (result && returnedExtraData != NULL) {
buffer_clear(returnedExtraData);
buffer_append_buffer(returnedExtraData, messageservicereauth_get_extra_data(messageservicereauth));
}

if (result && sequencenumber_match) {
sequencenumber_increment(fsmpico->serviceSeqNumber);
}
Expand Down
Loading