From 02771169d50140f419294cb5774c89dd1e0a4cd3 Mon Sep 17 00:00:00 2001 From: Krista Bennett Date: Fri, 3 Nov 2017 13:32:38 +0100 Subject: [PATCH] SYNC HAS RETURNED. Keysync still removed from Engine. --- Makefile | 2 + src/Makefile | 2 +- src/pEp_internal.h | 6 + src/sync.c | 288 +++++ src/sync.h | 417 +++++++ src/sync_actions.c | 434 ++++++++ src/sync_app.h | 34 + src/sync_impl.c | 971 +++++++++++++++++ src/sync_impl.h | 64 ++ sync/Makefile | 38 + sync/devicegroup.fsm | 354 ++++++ sync/fsm.yml2 | 19 + sync/functions.ysl2 | 15 + sync/gen_actions.ysl2 | 300 ++++++ sync/gen_dot.ysl2 | 42 + sync/gen_statemachine.ysl2 | 415 +++++++ sync/generated/README | 11 + sync/generated/sync_driver.c | 40 + sync/generated/sync_fsm.c | 1610 ++++++++++++++++++++++++++++ sync/generated/sync_fsm.h | 145 +++ sync/generated/sync_send_actions.c | 521 +++++++++ sync/skeletons/sync_actions.c | 564 ++++++++++ 22 files changed, 6291 insertions(+), 1 deletion(-) create mode 100644 src/sync.c create mode 100644 src/sync.h create mode 100644 src/sync_actions.c create mode 100644 src/sync_app.h create mode 100644 src/sync_impl.c create mode 100644 src/sync_impl.h create mode 100644 sync/Makefile create mode 100644 sync/devicegroup.fsm create mode 100644 sync/fsm.yml2 create mode 100644 sync/functions.ysl2 create mode 100644 sync/gen_actions.ysl2 create mode 100644 sync/gen_dot.ysl2 create mode 100644 sync/gen_statemachine.ysl2 create mode 100644 sync/generated/README create mode 100644 sync/generated/sync_driver.c create mode 100644 sync/generated/sync_fsm.c create mode 100644 sync/generated/sync_fsm.h create mode 100644 sync/generated/sync_send_actions.c create mode 100644 sync/skeletons/sync_actions.c diff --git a/Makefile b/Makefile index f585293d..916edf9f 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ endif all: $(MAKE) -C asn.1 generate $(MAKE) -C asn.1 + $(MAKE) -C sync $(MAKE) -C src all .PHONY: install @@ -40,6 +41,7 @@ clean: $(MAKE) -C src clean $(MAKE) -C test clean $(MAKE) -C db clean + $(MAKE) -C sync clean $(MAKE) -C asn.1 clean rm -rf test_home diff --git a/src/Makefile b/src/Makefile index 4944ff96..6a1638eb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -86,7 +86,7 @@ install: $(TARGET) mkdir -p "$(PREFIX)/lib/" cp $< $(PREFIX)/lib/ mkdir -p $(PREFIX)/include/pEp - cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h cryptotech.h blacklist.h openpgp_compat.h $(PREFIX)/include/pEp/ + cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h cryptotech.h sync.h sync_fsm.h sync_app.h blacklist.h openpgp_compat.h $(PREFIX)/include/pEp/ .PHONY: uninstall uninstall: diff --git a/src/pEp_internal.h b/src/pEp_internal.h index b3067f6f..ae01d57d 100644 --- a/src/pEp_internal.h +++ b/src/pEp_internal.h @@ -101,6 +101,7 @@ #include "keymanagement.h" #include "cryptotech.h" #include "transport.h" +#include "sync.h" #define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR; @@ -167,9 +168,14 @@ struct _pEpSession { void *examine_management; void *sync_management; void *sync_obj; + messageToSend_t messageToSend; + notifyHandshake_t notifyHandshake; + inject_sync_msg_t inject_sync_msg; + retrieve_next_sync_msg_t retrieve_next_sync_msg; // key sync pEpSession* sync_session; + DeviceState_state sync_state; void* sync_state_payload; char sync_uuid[37]; time_t LastCannotDecrypt; diff --git a/src/sync.c b/src/sync.c new file mode 100644 index 00000000..099e866f --- /dev/null +++ b/src/sync.c @@ -0,0 +1,288 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "pEp_internal.h" + +#include +#include + +#include "asn1_helper.h" +#include "../asn.1/DeviceGroup-Protocol.h" + +// receive_sync_msg is defined in the sync_impl + +PEP_STATUS receive_sync_msg( + PEP_SESSION session, + sync_msg_t *sync_msg, + time_t *timeout + ); + +DYNAMIC_API PEP_STATUS register_sync_callbacks( + PEP_SESSION session, + void *management, + messageToSend_t messageToSend, + notifyHandshake_t notifyHandshake, + inject_sync_msg_t inject_sync_msg, + retrieve_next_sync_msg_t retrieve_next_sync_msg + ) +{ + assert(session && management && messageToSend && notifyHandshake && inject_sync_msg && retrieve_next_sync_msg); + if (!(session && management && messageToSend && notifyHandshake && inject_sync_msg && retrieve_next_sync_msg)) + return PEP_ILLEGAL_VALUE; + + pEpUUID uuid; + uuid_generate_random(uuid); + uuid_unparse_upper(uuid, session->sync_uuid); + + session->sync_management = management; + session->messageToSend = messageToSend; + session->notifyHandshake = notifyHandshake; + session->inject_sync_msg = inject_sync_msg; + session->retrieve_next_sync_msg = retrieve_next_sync_msg; + + // start state machine + session->sync_state = InitState; + time_t unused = 0; + PEP_STATUS status = fsm_DeviceState_inject(session, Init, NULL, NULL, &unused); + if (status != PEP_STATUS_OK) + unregister_sync_callbacks(session); + + return status; +} + +DYNAMIC_API PEP_STATUS attach_sync_session( + PEP_SESSION session, + PEP_SESSION sync_session + ) +{ + assert(session && sync_session && sync_session->sync_management && sync_session->inject_sync_msg ); + if (!(session && sync_session && sync_session->sync_management && sync_session->inject_sync_msg )) + return PEP_ILLEGAL_VALUE; + + session->sync_session = sync_session; + // memcpy(session->sync_uuid, sync_session->sync_uuid, 37); + + // session->sync_management = sync_session->sync_management; + // session->inject_sync_msg = sync_session->inject_sync_msg; + + return PEP_STATUS_OK; +} + +DYNAMIC_API PEP_STATUS detach_sync_session(PEP_SESSION session) +{ + assert(session); + if (!(session)) + return PEP_ILLEGAL_VALUE; + + session->sync_session = session; + // memset(session->sync_uuid, 0, 37); + + // session->sync_management = NULL; + // session->inject_sync_msg = NULL; + + return PEP_STATUS_OK; +} + +int call_inject_sync_msg(PEP_SESSION session, void *msg) +{ + if(session->sync_session->inject_sync_msg && + session->sync_session->sync_management) + return session->sync_session->inject_sync_msg(msg, + session->sync_session->sync_management); + else + return PEP_SYNC_NO_INJECT_CALLBACK; +} + +DYNAMIC_API void unregister_sync_callbacks(PEP_SESSION session) { + // stop state machine + session->sync_state = DeviceState_state_NONE; + + // unregister + session->sync_management = NULL; + session->messageToSend = NULL; + session->notifyHandshake = NULL; + session->inject_sync_msg = NULL; + session->retrieve_next_sync_msg = NULL; +} + +DYNAMIC_API PEP_STATUS deliverHandshakeResult( + PEP_SESSION session, + Identity partner, + sync_handshake_result result + ) +{ + assert(session); + if (!session) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + DeviceState_event event; + bool need_partner = false; + + switch (result) { + case SYNC_HANDSHAKE_CANCEL: + event = Cancel; + break; + case SYNC_HANDSHAKE_ACCEPTED: + { + event = HandshakeAccepted; + need_partner = true; + break; + } + case SYNC_HANDSHAKE_REJECTED: + { + event = HandshakeRejected; + need_partner = true; + break; + } + default: + return PEP_ILLEGAL_VALUE; + } + + pEp_identity *_partner = NULL; + if(need_partner){ + _partner = identity_dup(partner); + if (_partner == NULL) + return PEP_OUT_OF_MEMORY; + } + status = inject_DeviceState_event(session, event, _partner, NULL); + + return status; +} + +DYNAMIC_API PEP_STATUS do_sync_protocol( + PEP_SESSION session, + void *obj + ) +{ + sync_msg_t *msg = NULL; + PEP_STATUS status = PEP_STATUS_OK; + time_t timeout = 0; + + assert(session && session->retrieve_next_sync_msg); + assert(obj); + + if (!(session && session->retrieve_next_sync_msg) || !obj) + return PEP_ILLEGAL_VALUE; + + log_event(session, "sync_protocol thread started", "pEp sync protocol", NULL, NULL); + + session->sync_obj = obj; + + while (true) + { + msg = (sync_msg_t *) session->retrieve_next_sync_msg(session->sync_management, &timeout); + if(msg == NULL && timeout == 0) + break; + else if(msg == NULL && timeout != 0){ + status = fsm_DeviceState_inject(session, Timeout, NULL, NULL, &timeout); +#ifndef NDEBUG + char buffer[MAX_LINELENGTH]; + memset(buffer, 0, MAX_LINELENGTH); + snprintf(buffer, MAX_LINELENGTH, "problem with timeout event : %d\n", (int) status); + log_event(session, buffer, "pEp sync protocol", NULL, NULL); + continue; +#endif + } + else { + status = receive_sync_msg(session, msg, &timeout); + if (status != PEP_STATUS_OK && status != PEP_MESSAGE_IGNORE) { +#ifndef NDEBUG + char buffer[MAX_LINELENGTH]; + memset(buffer, 0, MAX_LINELENGTH); + snprintf(buffer, MAX_LINELENGTH, "problem with msg received: %d\n", (int) status); + log_event(session, buffer, "pEp sync protocol", NULL, NULL); +#endif + } + } + } + + log_event(session, "sync_protocol thread shutdown", "pEp sync protocol", NULL, NULL); + + session->sync_obj = NULL; + + return PEP_STATUS_OK; +} + +DYNAMIC_API PEP_STATUS decode_sync_msg( + const char *data, + size_t size, + char **text + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(data && text); + if (!(data && text)) + return PEP_ILLEGAL_VALUE; + + *text = NULL; + + DeviceGroup_Protocol_t *msg = NULL; + uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **) &msg, + data, size); + if (!msg) + return PEP_SYNC_ILLEGAL_MESSAGE; + + growing_buf_t *dst = new_growing_buf(); + if (!dst) { + status = PEP_OUT_OF_MEMORY; + goto the_end; + } + + asn_enc_rval_t er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, + XER_F_BASIC, (asn_app_consume_bytes_f *) consume_bytes, (void *) dst); + if (er.encoded == -1) { + status = PEP_CANNOT_ENCODE; + goto the_end; + } + + *text = dst->data; + dst->data = NULL; + +the_end: + free_growing_buf(dst); + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + return status; +} + +DYNAMIC_API PEP_STATUS encode_sync_msg( + const char *text, + char **data, + size_t *size + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(text && data && size); + if (!(text && data && size)) + return PEP_ILLEGAL_VALUE; + + *data = NULL; + *size = 0; + + DeviceGroup_Protocol_t *msg = NULL; + asn_dec_rval_t dr = xer_decode(NULL, &asn_DEF_DeviceGroup_Protocol, + (void **) &msg, (const void *) text, strlen(text)); + if (dr.code != RC_OK) { + status = PEP_SYNC_ILLEGAL_MESSAGE; + goto the_end; + } + + char *payload = NULL; + ssize_t _size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol, + NULL, msg, (void **) &payload); + if (_size == -1) { + status = PEP_CANNOT_ENCODE; + goto the_end; + } + + *data = payload; + *size = (size_t) _size; + +the_end: + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + return status; +} + diff --git a/src/sync.h b/src/sync.h new file mode 100644 index 00000000..2e9748f6 --- /dev/null +++ b/src/sync.h @@ -0,0 +1,417 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +/* +==================================== +Engine/adapter/app KeySync interface +==================================== + + + Engine | Adapter | App + | | + . . . . . . . . . . . .|. . . . . . . . . . . . . . .|. . Attached session . + ,---------, | | + ,-| decrypt |<--------------------------------------- Incomming message + | | message | | | + | '---------' | | + | ,----------, | | + |-| myself |<-------------------------------------- Create new account + | | (keygen) | | | + | '----------' | | + | ,-----------, | | + |-| deliver |<------------------------------------------- Accept/reject + | | handshake | | KeySync | handshake + | | result | | Message | + | '-----------' | Queue | + | | ,---, | + '-----------------------inject_sync_msg---->| | | + . . . . . . . . . . . .|. . . . . . . . . . . |---| .|. . . . Sync session . + * * * * * * * * * * * * * * * *| |* | + | |---| | + * ,------------------retrieve_next_sync_msg-| |* | + ,-v--------, | '---' | + * | Driver | | * | + '----------' | | + * ||'-event-----, | * | + |'--partner--,| | | + * '---extra---,|| | SYNC THREAD *<-------------- Start Sync + ,---vvv---, | | + * ,----| FSM | | * | + | '---------' | | + * | ,-------, | * | + '->|actions|---------messageToSend-------------------> Send mail to self + * '-------' | * | + '-------------notifyHandshake-----------------> Ask for handshake + * | * | display group status + | | + * * * * * * * * |* * * * * * * * * * | + | | + +Emails to self +-------------- + +With e-mail as a transport KeySync message handling is done when an incoming +email to self is passed to decrypt_message(), assuming that all incoming email +messages are passed to decrypt_massage(). + +In case of an email containing a KeySync paload, KeySync may consume or ignore +the message. decrypt_message() signals this to the app with decrypt flags +PEP_decrypt_flag_consume and PEP_decrypt_flag_ignore. + +In case of PEP_decrypt_flag_consume, app should delete the message. +In case of PEP_decrypt_flag_ignore, app should ignore message. +In both cases, message should be hidden. + +States, events, actions +----------------------- + +In the engine, KeySync is implemented through a finite state machine (FSM) [1]. +KeySync state machine is driven [2] by events, triggering actions [3] and +transitions to new states. + +Events happen on : + + - decryption of email messages + + - key generation + + - user interaction through the app + + - timeout when staying too long in some particular states. + +[1] sync/devicegroup.fsm , src/sync_fsm.c (generated) +[2] src/sync_driver.c (generated) +[3] src/sync_actions.c , src/sync_send_actions.c (generated) + +Sync session, attached sessions +------------------------------- + +To use KeySync, the adapter has to create a session dedicated to handle the +protocol, register some callbacks [4] to the engine, and then call protocol's +event consumer loop [5] in a dedicated thread. KeySync actions are executed as +callback invoked from that thread. + +When a session is attached [6] to a KeySync session, decryption of pEp email +messages in the attached session may trigger operations in KeySync session. In +case of an adapter capable to serve multiple apps, each app is associated to a +different KeySync session, and sessions created for use in that app are +attached to that session. + +Adapters present different approaches regarding session and client abstraction, +and may not propose to explicitely create or attach session or sync session. + +[4] register_sync_callbacks() +[5] do_sync_protocol() +[6] attach_sync_session() + +KeySync Messages and queue +-------------------------- + +KeySync messages [7], not to be confused with pEp (email) messages, are either +directly events to be processed by the state machine, or KeySync payloads +collected from decrypted messages. + +KeySync messages can be emitted by different sessions, and could naturally come +from different threads. They must be serialized in a locked queue. +KeySync messages queue is implemented by adapter, along with thread handling +KeySync protocol. + +Attached sessions inject [8] KeySync messages in the queue. Protocol loop +retrieves [9] them from the queue. KeySync message is received [10] by the +state machine, where event, partner and extra parameters are eventually deduced +from payload. + +A state timeout event is a particular case. It doesn't traverse the queue, and +isn't emitted by a session. It is triggered by a timeout on the retrieve +operation. Value of the timeout is determined when entering a new state, and is +passed as a parameter of the call to the blocking queue retrieve operation on +next protocol loop iteraton. + +[7] type sync_msg_t +[8] callback inject_sync_msg +[9] callback retrieve_next_sync_msg +[10] receive_sync_msg() (src/sync_impl.c) + +Application callbacks +--------------------- + +Some Keysync actions require the application to act, through callbacks : + + - messageToSend : send pEp messages through app's transport. + Messages are already encrypted and just need to be passed as-is to + transport for transmission, as for messages returned by encrypt_message(). + + - notifyHandshake : display KeySync status and handshake to the user. + notifyHandshake callback receives 2 identities, 'me' and 'partner', together + with a sync_handshake_signal enum : + + SYNC_NOTIFY_INIT_ADD_OUR_DEVICE : + Device (me) is sole, about to enter a group (partner). + App displays trustwords, and requests user accept or reject + App calls deliverHandshakeResult with user's answer + + SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE : + Device (me) is grouped, another device (partner) wants to join group. + App displays trustwords, and requests user accept or reject + App calls deliverHandshakeResult with user's answer + + SYNC_NOTIFY_INIT_FORM_GROUP : + Device (me) is forming a group, including another device (partner) + App displays trustwords, and requests user accept or reject + App calls deliverHandshakeResult with user's answer + + SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE + Device (me) is grouped and will leave current group to join another + device's (partner) group. + App displays trustwords, and requests user accept or reject + App calls deliverHandshakeResult with user's answer + + + SYNC_NOTIFY_TIMEOUT : + KeySync operation timed out. + Identities are set reflecting peers involved in aborted operation. + App displays error message. No feedback to engine. + + SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED, + New device was added to group. + App displays message. No feedback to engine. + + SYNC_NOTIFY_ACCEPTED_GROUP_CREATED + New group created. + App displays message. No feedback to engine. + + SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED + New device was moved from one group to another. + App displays message. No feedback to engine. + + To deliver handshake result back to engine once user reacted, + deliver_handshake_result is used. Result can be : + + SYNC_HANDSHAKE_CANCEL + Gives no answer. User doesn't know id TrustWord are good or bad. + For example in case peering device is away. + Handshake will re-appear later. + + SYNC_HANDSHAKE_ACCEPTED + Trustwords match with other device and user accepts handshake. + + SYNC_HANDSHAKE_REJECTED + Trustwords do not match with any device and user rejects handshake. +*/ + +#pragma once + +#include "message.h" +#include "sync_fsm.h" +#include "sync_app.h" + +// this module is for being used WITHOUT the Transport API in transport.h +// DO NOT USE IT WHEN USING Transport API! + + +#ifdef __cplusplus +extern "C" { +#endif + +// messageToSend() - send a message +// +// parameters: +// obj (in) object handle (implementation defined) +// msg (in) message struct with message to send +// +// return value: +// PEP_STATUS_OK or any other value on error +// +// caveat: +// the ownership of msg goes to the callee + +typedef PEP_STATUS (*messageToSend_t)(void *obj, message *msg); + +// notifyHandshake() - notify UI about sync handshaking process +// +// parameters: +// obj (in) object handle (implementation defined) +// me (in) own identity +// partner (in) identity of partner +// signal (in) reason of the notification +// +// return value: +// PEP_STATUS_OK or any other value on error +// +// caveat: +// ownership of self and partner go to the callee + +typedef PEP_STATUS (*notifyHandshake_t)( + void *obj, + pEp_identity *me, + pEp_identity *partner, + sync_handshake_signal signal + ); + +typedef enum _sync_handshake_result { + SYNC_HANDSHAKE_CANCEL = -1, + SYNC_HANDSHAKE_ACCEPTED = 0, + SYNC_HANDSHAKE_REJECTED = 1 +} sync_handshake_result; + +// deliverHandshakeResult() - give the result of the handshake dialog +// +// parameters: +// session (in) session handle +// result (in) handshake result + +DYNAMIC_API PEP_STATUS deliverHandshakeResult( + PEP_SESSION session, + Identity partner, + sync_handshake_result result + ); + +// sync_msg_t - items queued for serialized handling by protocol engine +typedef struct _sync_msg_t sync_msg_t; + +// inject_sync_msg - inject sync protocol message +// +// parameters: +// msg (in) message to inject +// management (in) application defined +// +// *** BEWARE: msg is 1st parameter, obj is second!!! *** +// return value: +// 0 if msg could be stored successfully or nonzero otherwise + +typedef int (*inject_sync_msg_t)(void *msg, void *management); + + +// retrieve_next_sync_msg - receive next sync message +// +// parameters: +// management (in) application defined +// timeout (in,out) do not wait longer than timeout for message +// timeout == NULL or *timeout == 0 is blocking +// +// return value: +// next message, then timeout[out] == remaining time +// NULL and timeout[out] != 0 for timeout occurence +// NULL and timeout[out] == 0 for termination + +typedef void *(*retrieve_next_sync_msg_t)(void *management, time_t *timeout); + + +// register_sync_callbacks() - register adapter's callbacks +// +// parameters: +// session (in) session where to store obj handle +// management (in) application defined +// messageToSend (in) callback for sending message +// notifyHandshake (in) callback for doing the handshake +// retrieve_next_sync_msg (in) callback for receiving sync messages +// +// return value: +// PEP_STATUS_OK or any other value on errror +// +// caveat: +// call that BEFORE you're using any other part of the engine + +DYNAMIC_API PEP_STATUS register_sync_callbacks( + PEP_SESSION session, + void *management, + messageToSend_t messageToSend, + notifyHandshake_t notifyHandshake, + inject_sync_msg_t inject_sync_msg, + retrieve_next_sync_msg_t retrieve_next_sync_msg + ); + +// attach_sync_session() - attach session to a session running keysync state machine +// +// parameters: +// session (in) session to attach +// sync_session (in) session running keysync +// +// return value: +// PEP_STATUS_OK or any other value on errror +// +// caveat: +// register_sync_callbacks must have been called on sync_session +// call that BEFORE you're using that session in any other part of the engine + +DYNAMIC_API PEP_STATUS attach_sync_session( + PEP_SESSION session, + PEP_SESSION sync_session + ); + +// detach_sync_session() - detach previously attached sync session +// +// parameters: +// session (in) session to detach + +DYNAMIC_API PEP_STATUS detach_sync_session(PEP_SESSION session); + +// unregister_sync_callbacks() - unregister adapter's callbacks +// +// parameters: +// session (in) session to unregister + +DYNAMIC_API void unregister_sync_callbacks(PEP_SESSION session); + +// do_sync_protocol() - function to be run on an extra thread +// +// parameters: +// session pEp session to use +// retrieve_next_sync_msg pointer to retrieve_next_identity() callback +// which returns at least a valid address field in +// the identity struct +// obj application defined sync object +// +// return value: +// PEP_STATUS_OK if thread has to terminate successfully or any other +// value on failure +// +// caveat: +// to ensure proper working of this library, a thread has to be started +// with this function immediately after initialization + +DYNAMIC_API PEP_STATUS do_sync_protocol( + PEP_SESSION session, + void *obj + ); + +// free_sync_msg() - free sync_msg_t struct when not passed to do_sync_protocol +// +// parameters: +// sync_msg (in) pointer to sync_msg_t struct to free. +// pointer can be NULL. + +DYNAMIC_API void free_sync_msg(sync_msg_t *sync_msg); + +// decode_sync_msg() - decode sync message from PER into XER +// +// parameters: +// data (in) PER encoded data +// size (in) size of PER encoded data +// text (out) XER text of the same sync message + +DYNAMIC_API PEP_STATUS decode_sync_msg( + const char *data, + size_t size, + char **text + ); + + +// encode_sync_msg() - encode sync message from XER into PER +// +// parameters: +// text (in) string with XER text of the sync message +// data (out) PER encoded data +// size (out) size of PER encoded data + +DYNAMIC_API PEP_STATUS encode_sync_msg( + const char *text, + char **data, + size_t *size + ); + + +#ifdef __cplusplus +} +#endif + diff --git a/src/sync_actions.c b/src/sync_actions.c new file mode 100644 index 00000000..669aea54 --- /dev/null +++ b/src/sync_actions.c @@ -0,0 +1,434 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// Actions for DeviceState state machine + +#include +#include "pEp_internal.h" +#include "message.h" +#include "sync_fsm.h" +#include "sync_impl.h" +#include "map_asn1.h" +#include "baseprotocol.h" + +// conditions + +int deviceGrouped(PEP_SESSION session) +{ + assert(session); + if (!session) + return invalid_condition; // error + + char *devgrp = NULL; + int res = 0; + PEP_STATUS status; + + status = get_device_group(session, &devgrp); + + if (status == PEP_STATUS_OK && devgrp && devgrp[0]) + res = 1; + + free(devgrp); + + return res; +} + +int keyElectionWon(PEP_SESSION session, Identity partner) +{ + assert(session); + assert(partner); + if (!(session && partner)) + return invalid_condition; // error + + int partner_is_group = partner->flags & PEP_idf_devicegroup; + + if (deviceGrouped(session)){ + // existing group always wins against sole device + if(!partner_is_group) + return 1; + } else { + // sole device always loses against group + if(partner_is_group) + return 0; + } + + // two groups or two sole are elected based on key age + // key created first wins + + Identity me = NULL; + PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID, + &me); + if (status == PEP_OUT_OF_MEMORY) + return invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return invalid_condition; // error + + int result = invalid_condition; // error state has to be overwritten + + time_t own_created; + time_t partners_created; + + status = key_created(session, me->fpr, &own_created); + if (status != PEP_STATUS_OK) + goto the_end; + + status = key_created(session, partner->fpr, &partners_created); + if (status != PEP_STATUS_OK) + goto the_end; + + if (own_created > partners_created) + result = 0; + else + result = 1; + +the_end: + free_identity(me); + return result; +} + +int sameIdentities(PEP_SESSION session, Identity a, Identity b) +{ + assert(session); + assert(a); + assert(b); + + if (!(session && a && b)) + return invalid_condition; // error + + if (a->fpr == NULL || b->fpr == NULL || + (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) || + a->address == NULL || b->address == NULL || + strcmp(a->address, b->address) != 0 || + a->user_id == NULL || b->user_id == NULL || + strcmp(a->user_id, b->user_id) != 0) + return 0; + return 1; +} + +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b) +{ + assert(session); + assert(a); + assert(b); + + if (!(session && a && b)) + return invalid_condition; // error + + if (a->fpr == NULL || b->fpr == NULL || + (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) || + a->address == NULL || b->address == NULL || + strcmp(a->address, b->address) != 0) + return 0; + return 1; +} + +// actions + +PEP_STATUS _notifyHandshake( + PEP_SESSION session, + Identity partner, + sync_handshake_signal signal + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + assert(session->notifyHandshake); + if (!session->notifyHandshake) + return PEP_SYNC_NO_NOTIFY_CALLBACK; + + // notifyHandshake take ownership of given identities + pEp_identity *me = NULL; + status = get_identity(session, partner->address, PEP_OWN_USERID, &me); + if (status != PEP_STATUS_OK) + goto error; + + pEp_identity *_partner = NULL; + _partner = identity_dup(partner); + if (_partner == NULL){ + status = PEP_OUT_OF_MEMORY; + goto error; + } + + status = session->notifyHandshake(session->sync_obj, me, _partner, signal); + if (status != PEP_STATUS_OK) + goto error; + + return status; + +error: + free_identity(me); + return status; +} + +// acceptHandshake() - stores acception of partner +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS acceptHandshake( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + assert(extra == NULL); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + status = trust_personal_key(session, partner); + + return status; +} + + +// rejectHandshake() - stores rejection of partner +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS rejectHandshake( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + assert(extra == NULL); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // TODO : disable sync globally if not in a group + status = set_identity_flags(session, partner, + partner->flags | PEP_idf_not_for_sync); + + return status; +} + +PEP_STATUS _storeGroupKeys( + PEP_SESSION session, + identity_list *group_keys + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + for (identity_list *il = group_keys; il && il->ident; il = il->next) { + + if (strcmp(il->ident->user_id, PEP_OWN_USERID)!=0) { + assert(0); + continue; + } + // Check that identity isn't excluded from sync. + pEp_identity *stored_identity = NULL; + status = get_identity(session, il->ident->address, PEP_OWN_USERID, + &stored_identity); + if (status == PEP_STATUS_OK) { + if(stored_identity->flags & PEP_idf_not_for_sync){ + free_identity(stored_identity); + continue; + } + free_identity(stored_identity); + } + + status = set_identity(session, il->ident); + if (status != PEP_STATUS_OK) + break; + } + + return status; +} + + +// storeGroupKeys() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// _group_keys (in) group keys received from partner +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS storeGroupKeys( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *group_keys_extra_ + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + assert(group_keys_extra_); + if (!(session && partner && group_keys_extra_)) + return PEP_ILLEGAL_VALUE; + + group_keys_extra_t *group_keys_extra = + (group_keys_extra_t*) group_keys_extra_; + identity_list *group_keys = group_keys_extra->group_keys; + char *group_id = group_keys_extra->group_id; + + status = _storeGroupKeys(session, group_keys); + if (status != PEP_STATUS_OK) + return status; + + // set group id according to given group-id + status = set_device_group(session, group_id); + if (status != PEP_STATUS_OK) + return status; + + return status; +} + +// storeGroupUpdate() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// _group_keys (in) group keys received from partner +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS storeGroupUpdate( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *group_keys_ + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + assert(group_keys_); + if (!(session && partner && group_keys_)) + return PEP_ILLEGAL_VALUE; + + identity_list *group_keys = (identity_list*) group_keys_; + + status = _storeGroupKeys(session, group_keys); + + + return status; +} + +// makeGroup() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) ignored +// extra (in) ignored +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS makeGroup( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + + // make a new uuid + char new_uuid[37]; + pEpUUID uuid; + uuid_generate_random(uuid); + uuid_unparse_upper(uuid, new_uuid); + + // take that new uuid as group-id + status = set_device_group(session, new_uuid); + + return status; +} + +// renewUUID() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) ignored +// extra (in) ignored +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS renewUUID( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + + // change sync_uuid when entering group + // thus ignoring unprocessed handshakes + // addressed to previous self (sole) once in. + pEpUUID uuid; + uuid_generate_random(uuid); + uuid_unparse_upper(uuid, session->sync_uuid); + + return status; +} + +// leaveGroup() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) ignored +// extra (in) ignored +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS leaveGroup( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + + status = set_device_group(session, NULL); + + return status; +} diff --git a/src/sync_app.h b/src/sync_app.h new file mode 100644 index 00000000..dfda04fe --- /dev/null +++ b/src/sync_app.h @@ -0,0 +1,34 @@ +// +// sync_app.h +// pEpEngine +// +// Created by Dirk Zimmermann on 16.05.17. +// Copyright © 2017 Edouard Tisserant. All rights reserved. +// + +#ifndef sync_app_h +#define sync_app_h + +// TODO add this to generated code. +typedef enum _sync_handshake_signal { + SYNC_NOTIFY_UNDEFINED = 0, + + // request show handshake dialog + SYNC_NOTIFY_INIT_ADD_OUR_DEVICE, + SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE, + SYNC_NOTIFY_INIT_FORM_GROUP, + SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE, + + // handshake process timed out + SYNC_NOTIFY_TIMEOUT, + + // handshake accepted by user + SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED, + SYNC_NOTIFY_ACCEPTED_GROUP_CREATED, + SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED, + + // handshake dialog must be closed + SYNC_NOTIFY_OVERTAKEN +} sync_handshake_signal; + +#endif /* sync_app_h */ diff --git a/src/sync_impl.c b/src/sync_impl.c new file mode 100644 index 00000000..58b11de1 --- /dev/null +++ b/src/sync_impl.c @@ -0,0 +1,971 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "platform.h" + +// it seems pEp_internal.h needs to be the first pEp include due to the +// #define for the dllimport / dllexport DYNAMIC_API stuff. +#include "pEp_internal.h" + +#include "sync_impl.h" +#include "keymanagement.h" +#include "message_api.h" +#include "map_asn1.h" +#include "baseprotocol.h" + +#define SYNC_VERSION_MAJOR 1 +#define SYNC_VERSION_MINOR 0 + +#define SYNC_INHIBIT_TIME (60*10) +#define SYNC_MSG_EXPIRE_TIME (60 * 10) + +struct _sync_msg_t { + bool is_a_message; + union { + DeviceGroup_Protocol_t *message; + struct { + DeviceState_event event; + Identity partner; + void *extra; + } event; + } u; +}; + +static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid) +{ + return strncmp(session->sync_session->sync_uuid, + (const char*)uuid->buf, uuid->size) == 0; +} + +static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid, char** our_group) +{ + PEP_STATUS status = PEP_STATUS_OK; + char *devgrp = NULL; + + if(our_group == NULL || *our_group == NULL) + status = get_device_group(session, &devgrp); + else + devgrp = *our_group; + + bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] && + strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0); + + if(our_group == NULL) + free(devgrp); + else if(*our_group == NULL) + *our_group = devgrp; + + return res; +} + +PEP_STATUS receive_sync_msg( + PEP_SESSION session, + sync_msg_t *sync_msg, + time_t *timeout + ) +{ + PEP_STATUS status; + void *extra = NULL; + Identity partner = NULL; + DeviceState_event event = DeviceState_event_NONE; + assert(session && sync_msg); + if (!(session && sync_msg)) + return PEP_ILLEGAL_VALUE; + + bool msgIsFromGroup = false; + if(sync_msg->is_a_message){ + DeviceGroup_Protocol_t *msg = sync_msg->u.message; + assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING); + if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){ + status = PEP_OUT_OF_MEMORY; + goto error; + } + + partner = Identity_to_Struct(&msg->header.me, NULL); + if (!partner){ + status = PEP_OUT_OF_MEMORY; + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + + msgIsFromGroup = msg->header.devicegroup; + + switch (msg->payload.present) { + case DeviceGroup_Protocol__payload_PR_beacon: + event = Beacon; + break; + + case DeviceGroup_Protocol__payload_PR_handshakeRequest: + { + // re-check uuid in case sync_uuid or group changed while in the queue + char *own_group_id = NULL; + bool is_for_me = _is_own_uuid(session, + msg->payload.choice.handshakeRequest.partner_id); + bool is_for_group = !is_for_me && _is_own_group_uuid(session, + msg->payload.choice.handshakeRequest.partner_id, &own_group_id); + if (!(is_for_me || is_for_group)){ + status = PEP_MESSAGE_IGNORE; + goto error; + } + + UTF8String_t *guuid = msg->payload.choice.handshakeRequest.group_id; + if(msgIsFromGroup && guuid && guuid->buf && guuid->size) { + bool is_from_own_group = _is_own_group_uuid(session, + guuid, &own_group_id); + + // Filter handshake requests from own group + if(is_from_own_group) { + status = PEP_MESSAGE_IGNORE; + goto error; + } + + // if it comes from another group, + // we want to communicate with that group + // insert group_id given in handshake request + // into partner's id + + free(partner->user_id); + partner->user_id = strndup((const char*)guuid->buf, guuid->size); + if(partner->user_id == NULL){ + status = PEP_OUT_OF_MEMORY; + goto error; + } + + // if it comes from another group, and we are grouped, + // then this is groupmerge + } + + event = HandshakeRequest; + break; + + } + case DeviceGroup_Protocol__payload_PR_updateRequest: + event = UpdateRequest; + break; + + case DeviceGroup_Protocol__payload_PR_groupKeys: + { + // re-check uuid in case sync_uuid or group_uuid changed while in the queue + char *own_group_id = NULL; + UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id; + bool is_for_me = _is_own_uuid(session, puuid); + bool is_for_group = !is_for_me && + _is_own_group_uuid(session, + puuid, &own_group_id); + if (!(is_for_me || is_for_group)){ + status = PEP_MESSAGE_IGNORE; + goto error; + } + + UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id; + + // GroupKeys come from groups, no choice + if(!(msgIsFromGroup && guuid && guuid->buf && guuid->size)) { + status = PEP_SYNC_ILLEGAL_MESSAGE; + goto error; + } + + // Filter groupKeys from own group + bool is_from_own_group = _is_own_group_uuid(session, + guuid, + &own_group_id); + if(is_from_own_group) { + // FixMe : protocol shouldn't allow this + status = PEP_SYNC_ILLEGAL_MESSAGE; + goto error; + } + + // insert group_id given in groupKeys into partner's id + free(partner->user_id); + partner->user_id = strndup((const char*)guuid->buf, guuid->size); + if(partner->user_id == NULL){ + status = PEP_OUT_OF_MEMORY; + goto error; + } + + // if it comes from another group, and we are grouped, + // then this is groupmerge's groupKeys + + group_keys_extra_t *group_keys_extra; + group_keys_extra = malloc(sizeof(group_keys_extra_t)); + if(group_keys_extra == NULL){ + status = PEP_OUT_OF_MEMORY; + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + + char *group_id = strndup((char*)guuid->buf, guuid->size); + + if (!group_id){ + status = PEP_OUT_OF_MEMORY; + free(group_keys_extra); + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + group_keys_extra->group_id = group_id; + + identity_list *group_keys = IdentityList_to_identity_list( + &msg->payload.choice.groupKeys.ownIdentities, + NULL); + if (!group_keys) { + status = PEP_OUT_OF_MEMORY; + free(group_id); + free(group_keys_extra); + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + group_keys_extra->group_keys = group_keys; + + extra = (void *) group_keys_extra; + event = GroupKeys; + + break; + } + case DeviceGroup_Protocol__payload_PR_groupUpdate: + { + identity_list *group_keys = IdentityList_to_identity_list( + &msg->payload.choice.groupUpdate.ownIdentities, NULL); + if (!group_keys) { + status = PEP_OUT_OF_MEMORY; + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + extra = (void *) group_keys; + event = GroupUpdate; + break; + } + + default: + status = PEP_SYNC_ILLEGAL_MESSAGE; + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + goto error; + } + + } + else{ + partner = sync_msg->u.event.partner; + extra = sync_msg->u.event.extra; + event = sync_msg->u.event.event; + } + + // Event inhibition, to limit mailbox and prevent cycles + time_t *last = NULL; + switch(event){ + case CannotDecrypt: + last = &session->LastCannotDecrypt; + break; + + case UpdateRequest: + last = &session->LastUpdateRequest; + break; + + default: + break; + } + + if(last != NULL){ + time_t now = time(NULL); + if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){ + status = PEP_STATEMACHINE_INHIBITED_EVENT; + goto error; + } + *last = now; + } + + // partner identity must be explicitely added DB to later + // be able to communicate securely with it. + if(partner){ + // protect virtual user IDs + if((strncmp("TOFU_", partner->user_id, 6) == 0 && + strlen(partner->user_id) == strlen(partner->address) + 6 && + strcmp(partner->user_id + 6, partner->address)) || + // protect own ID + (strcmp(PEP_OWN_USERID, partner->user_id) == 0)){ + status = PEP_SYNC_ILLEGAL_MESSAGE; + goto error; + } + + // partner IDs are UUIDs bound to session lifespan + // and therefore partner identities are not supposed + // to mutate over time, but just not be used anymore. + // It should then be safe to accept given identity if not + // already pre-existing + pEp_identity *stored_identity = NULL; + status = get_identity(session, + partner->address, + partner->user_id, + &stored_identity); + + if (!stored_identity) { + // make a safe copy of partner, with no flags or comm_type + pEp_identity *tmpident = new_identity(partner->address, + partner->fpr, + partner->user_id, + partner->username); + if (tmpident == NULL){ + status = PEP_OUT_OF_MEMORY; + goto error; + } + + // finaly add partner to DB + status = set_identity(session, tmpident); + assert(status == PEP_STATUS_OK); + if(status == PEP_STATUS_OK && msgIsFromGroup) + status = set_identity_flags(session, tmpident, PEP_idf_devicegroup); + free_identity(tmpident); + assert(status == PEP_STATUS_OK); + if (status != PEP_STATUS_OK) { + goto error; + } + } + else if (status == PEP_STATUS_OK) { + free_identity(stored_identity); + } + else + goto error; + } + + status = fsm_DeviceState_inject(session, event, partner, extra, timeout); + +error: + + free_identity(partner); + + switch(event){ + case GroupKeys: + { + free_group_keys_extra((group_keys_extra_t*)extra); + break; + } + case GroupUpdate: + { + identity_list *group_keys = (identity_list*) extra; + free_identity_list(group_keys); + break; + } + default: + assert(extra==NULL); + break; + } + + free(sync_msg); + + return status; +} + +// TODO: DYNAMIC_API was here, but broke the windows build. +// We need to check whether it belongs here or it's a bug. +/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg) +{ + if (!sync_msg) + return; + + if(sync_msg->is_a_message){ + DeviceGroup_Protocol_t *msg = sync_msg->u.message; + assert(msg); + if (!(msg)) + return; + + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + } + else{ + Identity partner = NULL; + partner = sync_msg->u.event.partner; + if(partner != NULL) + free_identity(partner); + } + + free(sync_msg); + + return; +} + +// from sync.c +int call_inject_sync_msg(PEP_SESSION session, void *msg); + +PEP_STATUS inject_DeviceState_event( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra) +{ + PEP_STATUS status; + + assert(session); + if (!(session)) + return PEP_ILLEGAL_VALUE; + + sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t)); + if(sync_msg == NULL) + return PEP_OUT_OF_MEMORY; + + sync_msg->is_a_message = false; + sync_msg->u.event.partner = partner; + sync_msg->u.event.extra = extra; + sync_msg->u.event.event = event; + + status = call_inject_sync_msg(session, sync_msg); + if (status == PEP_SYNC_NO_INJECT_CALLBACK){ + free(sync_msg); + } + + return status; +} + +PEP_STATUS receive_DeviceState_msg( + PEP_SESSION session, + message *src, + PEP_rating rating, + stringlist_t *keylist) +{ + assert(session && src); + if (!(session && src)) + return PEP_ILLEGAL_VALUE; + + bool consume = false; + bool discard = false; + bool force_keep_msg = false; + + for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) { + if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0 + && bl->size) { + DeviceGroup_Protocol_t *msg = NULL; + uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **) + &msg, bl->value, bl->size); + + if (msg) { + PEP_STATUS status = PEP_STATUS_OK; + + char *user_id = strndup((char *) msg->header.me.user_id->buf, + msg->header.me.user_id->size); + assert(user_id); + if (!user_id) { + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + return PEP_OUT_OF_MEMORY; + } + + // detect and mitigate address spoofing + Identity check_me = NULL; + char* null_terminated_address = + strndup((char *) msg->header.me.address->buf, + msg->header.me.address->size); + + if(null_terminated_address){ + status = get_identity(session, + null_terminated_address, + PEP_OWN_USERID, + &check_me); + free(null_terminated_address); + } + else + status = PEP_OUT_OF_MEMORY; + + if (status == PEP_OUT_OF_MEMORY) + goto free_all; + + free_identity(check_me); + + bool not_own_address = status != PEP_STATUS_OK; + status = PEP_STATUS_OK; + + if (not_own_address || + strncmp(src->from->address, + (char *) msg->header.me.address->buf, + msg->header.me.address->size) != 0 || + strncmp(src->to->ident->address, + (char *) msg->header.me.address->buf, + msg->header.me.address->size) != 0) { + consume = true; + goto free_all; + } + + // if encrypted, ensure that header.me.fpr match signer's fpr + if (rating >= PEP_rating_reliable && ( + !keylist || + !_same_fpr((char *) msg->header.me.fpr.buf, + msg->header.me.fpr.size, + keylist->value, + strlen(keylist->value)))) { + consume = true; + goto free_all; + } + + // check message expiry + if(src->recv) { + time_t expiry = timegm(src->recv) + SYNC_MSG_EXPIRE_TIME; + time_t now = time(NULL); + if(expiry != 0 && now != 0 && expiry < now){ + consume = true; + goto free_all; + } + } + + int32_t value = (int32_t) msg->header.sequence; + if (value < 1) { + status = PEP_SEQUENCE_VIOLATED; + } else { + status = sequence_value(session, (char *) user_id, + &value); + } + + if (status == PEP_STATUS_OK) { + switch (msg->payload.present) { + // HandshakeRequest needs encryption + case DeviceGroup_Protocol__payload_PR_handshakeRequest: + { + UTF8String_t *puuid = + msg->payload.choice.handshakeRequest.partner_id; + bool is_for_me = _is_own_uuid(session, puuid); + bool is_for_group = !is_for_me && + _is_own_group_uuid( + session, puuid, NULL); + + // Reject handshake requests not addressed to us + if (rating < PEP_rating_reliable || + !(is_for_me || is_for_group)){ + discard = true; + goto free_all; + } + + // do not consume handshake request for group + if(is_for_group){ + force_keep_msg = true; + } + break; + } + // accepting GroupKeys needs encryption and trust of peer device + case DeviceGroup_Protocol__payload_PR_groupKeys: + { + UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id; + bool is_for_me = _is_own_uuid(session, puuid); + bool is_for_group = !is_for_me && + _is_own_group_uuid(session, + puuid, NULL); + if (!keylist || rating < PEP_rating_reliable || + // message is only consumed by instance it is addressed to + !(is_for_me || is_for_group)){ + discard = true; + goto free_all; + } + + // do not consume groupKeys for group + if(is_for_group){ + // This happens in case case of groupmerge + force_keep_msg = true; + } + + // Trust check disabled here but it still it should be safe. + // SameIdentity checks in state machine ensures that we only + // store groupkeys signed by device or group that have been + // previously accepted in handshake. + // + // // check trust of identity using user_id given in msg.header.me + // // to exacly match identity of device, the one trusted in + // // case of accepted handshake from a sole device + // pEp_identity *_from = new_identity(NULL, + // keylist->value, + // user_id, + // NULL); + // if (_from == NULL){ + // status = PEP_OUT_OF_MEMORY; + // goto free_all; + // } + // status = get_trust(session, _from); + // if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) { + + // // re-try with group_id instead, in case of handshake with pre-existing group + // UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id; + // free(_from->user_id); + // if ((_from->user_id = strndup((const char*)guuid->buf, guuid->size)) == NULL){ + // free_identity(_from); + // status = PEP_OUT_OF_MEMORY; + // goto free_all; + // } + // _from->comm_type = PEP_ct_unknown; + + // status = get_trust(session, _from); + // if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) { + // status = PEP_STATUS_OK; + // free_identity(_from); + // discard = true; + // goto free_all; + // } + // } + // free_identity(_from); + break; + } + case DeviceGroup_Protocol__payload_PR_groupUpdate: + case DeviceGroup_Protocol__payload_PR_updateRequest: + { + // inject message but don't consume it, so + // that other group members can also be updated + force_keep_msg = true; + + if (!keylist || rating < PEP_rating_reliable){ + discard = true; + goto free_all; + } + // GroupUpdate and UpdateRequests come from group. + // check trust relation in between signer key and + // own id to be sure. + pEp_identity *_from = new_identity(NULL, + keylist->value, + PEP_OWN_USERID, + NULL); + if (_from == NULL){ + status = PEP_OUT_OF_MEMORY; + goto free_all; + } + status = get_trust(session, _from); + if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_pEp) { + status = PEP_STATUS_OK; + free_identity(_from); + discard = true; + goto free_all; + } + free_identity(_from); + } + default: + break; + } + + + consume = true; + sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t)); + if(sync_msg == NULL){ + status = PEP_OUT_OF_MEMORY; + goto free_all; + } + sync_msg->is_a_message = true; + sync_msg->u.message = msg; + status = call_inject_sync_msg(session, sync_msg); + if (status != PEP_STATUS_OK){ + if (status == PEP_SYNC_NO_INJECT_CALLBACK){ + free(sync_msg); + } + goto free_all; + } + // don't free message now that it is in the queue + goto free_userid; + } + else if (status == PEP_OWN_SEQUENCE || status == PEP_SEQUENCE_VIOLATED) { + status = PEP_STATUS_OK; + discard = true; + goto free_all; + } + + free_all: + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); + free_userid: + free(user_id); + + if (status != PEP_STATUS_OK) + return status; + } + } + } + + if (force_keep_msg) { + return PEP_MESSAGE_IGNORE; + } + + if (consume && !session->keep_sync_msg) { + for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ; + spl = spl->next) { + if (spl->value->key && + strcasecmp(spl->value->key, "pEp-auto-consume") == 0) { + if (spl->value->value && + strcasecmp(spl->value->value, "yes") == 0) + return PEP_MESSAGE_CONSUME; + } + } + return PEP_MESSAGE_IGNORE; + } + + if(discard) + return PEP_MESSAGE_IGNORE; + + if (!session->keep_sync_msg) { + bloblist_t *last = NULL; + for (bloblist_t *bl = src->attachments; bl && bl->value; ) { + if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0) { + bloblist_t *b = bl; + bl = bl->next; + if (!last) + src->attachments = bl; + else + last->next = bl; + free(b->mime_type); + free(b->filename); + free(b->value); + free(b); + } + else { + last = bl; + bl = bl->next; + } + } + } + + return PEP_STATUS_OK; +} + +DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type) +{ + DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *) + calloc(1, sizeof(DeviceGroup_Protocol_t)); + assert(msg); + if (!msg) + return NULL; + msg->payload.present = type; + return msg; +} + +void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg) +{ + ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); +} + + +#ifndef NDEBUG +static int _append(const void *buffer, size_t size, void *appkey) +{ + char **dest_ptr = (char **)appkey; + size_t osize = strlen(*dest_ptr); + size_t nsize = size + osize; + *dest_ptr = realloc(*dest_ptr, nsize + 1); + if(*dest_ptr == NULL) return -1; + memcpy(*dest_ptr + osize, buffer, size); + (*dest_ptr)[nsize] = '\0'; + return 0; +} +#endif + +PEP_STATUS unicast_msg( + PEP_SESSION session, + const Identity partner, + DeviceState_state state, + DeviceGroup_Protocol_t *msg, + bool encrypted + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + char *payload = NULL; + message *_message = NULL; + pEp_identity *me = NULL; + pEp_identity *_me = NULL; + + assert(session && partner && state && msg); + if (!(session && partner && state && msg)) + return PEP_ILLEGAL_VALUE; + + assert(session->messageToSend); + if (!session->messageToSend) { + status = PEP_SEND_FUNCTION_NOT_REGISTERED; + goto error; + } + + msg->header.version.major = SYNC_VERSION_MAJOR; + msg->header.version.minor = SYNC_VERSION_MINOR; + + status = get_identity(session, partner->address, PEP_OWN_USERID, &me); + if (status != PEP_STATUS_OK) + goto error; + + int32_t seq = 0; + + status = sequence_value(session, session->sync_session->sync_uuid, &seq); + if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK) + goto error; + + msg->header.sequence = (long) seq; + + _me = identity_dup(me); + if (!_me) + goto enomem; + + free(_me->user_id); + _me->user_id = strndup(session->sync_session->sync_uuid, 36); + assert(_me->user_id); + if (!_me->user_id) + goto enomem; + + if (Identity_from_Struct(_me, &msg->header.me) == NULL) + goto enomem; + + free_identity(_me); + _me = NULL; + + msg->header.state = (long) state; + + bool devicegroup = deviceGrouped(session); + if (devicegroup) + msg->header.devicegroup = 1; + else + msg->header.devicegroup = 0; + + if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) { + status = PEP_CONTRAINTS_VIOLATED; + goto error; + } + + ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol, + NULL, msg, (void **) &payload); + if (size == -1) { + status = PEP_CANNOT_ENCODE; + goto error; + } + + status = prepare_message(me, partner, payload, size, &_message); + if (status != PEP_STATUS_OK) + goto error; + payload = NULL; + free_identity(me); + me = NULL; + +#ifndef NDEBUG + asn_enc_rval_t er; + er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, + XER_F_BASIC, _append, &_message->longmsg); + if(er.encoded == -1) + goto error; +#endif + + if (encrypted) { + if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys || + msg->payload.present == DeviceGroup_Protocol__payload_PR_groupUpdate) { + PEP_rating rating = PEP_rating_undefined; + status = outgoing_message_rating(session, _message, &rating); + if (status != PEP_STATUS_OK) + goto error; + if (rating < PEP_rating_trusted) { + status = PEP_SYNC_NO_TRUST; + goto error; + } + + stringlist_t *keylist = NULL; + status = _own_keys_retrieve(session, &keylist, PEP_idf_not_for_sync); + if (status != PEP_STATUS_OK) + goto error; + + for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) { + char *fpr = _keylist->value; + static char filename[MAX_LINELENGTH]; + int result = snprintf(filename, MAX_LINELENGTH, "file://%s-sec.asc", fpr); + if (result < 0) + goto enomem; + char *key = NULL; + size_t size = 0; + status = export_secrect_key(session, fpr, &key, &size); + if (status != PEP_STATUS_OK) + goto error; + bloblist_t *bl = bloblist_add(_message->attachments, + (char *) key, size, "application/pgp-keys", filename); + if (!bl) + goto enomem; + if (!_message->attachments) + _message->attachments = bl; + } + } + + message *_encrypted = NULL; + status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0); + if (status != PEP_STATUS_OK) + goto error; + free_message(_message); + _message = _encrypted; + } + else { + attach_own_key(session, _message); + } + + status = session->messageToSend(session->sync_obj, _message); + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_identity(_me); + free(payload); + free_message(_message); + free_identity(me); + return status; +} + +PEP_STATUS multicast_self_msg( + PEP_SESSION session, + DeviceState_state state, + DeviceGroup_Protocol_t *msg, + bool encrypted + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session && state && msg); + if (!(session && state && msg)) + return PEP_ILLEGAL_VALUE; + + identity_list *own_identities = NULL; + status = _own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync); + if (status != PEP_STATUS_OK) + return status; + + for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) { + pEp_identity *me = _i->ident; + + // FIXME: no deep copy for multicast supported yet + // DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t)); + // assert(_msg); + // if (_msg == NULL){ + // status = PEP_OUT_OF_MEMORY; + // goto error; + // } + // memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t)); + status = unicast_msg(session, me, state, msg, encrypted); + //status = unicast_msg(session, me, state, _msg, encrypted); + //free_DeviceGroup_Protocol_msg(_msg); + } + + free_identity_list(own_identities); + return PEP_STATUS_OK; + +// error: +// free_identity_list(own_identities); +// return status; +} + +void free_group_keys_extra(group_keys_extra_t* group_keys_extra) +{ + identity_list *group_keys = group_keys_extra->group_keys; + char *group_id = group_keys_extra->group_id; + free_identity_list(group_keys); + free(group_id); + free(group_keys_extra); +} + +group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* group_key_extra_src) +{ + group_keys_extra_t *group_key_extra_dst; + group_key_extra_dst = calloc(1,sizeof(group_keys_extra_t)); + if(group_key_extra_dst == NULL){ + return NULL; + } + + char *group_id = strdup(group_key_extra_src->group_id); + + if (group_key_extra_dst->group_id && !group_id){ + free(group_key_extra_dst); + return NULL; + } + group_key_extra_dst->group_id = group_id; + + identity_list *group_keys = identity_list_dup(group_key_extra_src->group_keys);; + if (!group_keys) { + free(group_id); + free(group_key_extra_dst); + return NULL; + } + group_key_extra_dst->group_keys = group_keys; + + return group_key_extra_dst; +} diff --git a/src/sync_impl.h b/src/sync_impl.h new file mode 100644 index 00000000..5af621c7 --- /dev/null +++ b/src/sync_impl.h @@ -0,0 +1,64 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#pragma once + +#include "../asn.1/DeviceGroup-Protocol.h" +#include "message.h" +#include "sync.h" +#include "sync_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _group_keys_extra { + identity_list *group_keys; + char *group_id; +} group_keys_extra_t; + +void free_group_keys_extra(group_keys_extra_t* groupkeys); +group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* groupkeys); + +PEP_STATUS receive_sync_msg( + PEP_SESSION session, + sync_msg_t *sync_msg, + time_t *timeout + ); + +PEP_STATUS inject_DeviceState_event( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra); + +PEP_STATUS receive_DeviceState_msg( + PEP_SESSION session, + message *src, + PEP_rating rating, + stringlist_t *keylist); + +DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type); +void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg); + +PEP_STATUS unicast_msg( + PEP_SESSION session, + const Identity partner, + DeviceState_state state, + DeviceGroup_Protocol_t *msg, + bool encrypted + ); + +PEP_STATUS multicast_self_msg( + PEP_SESSION session, + DeviceState_state state, + DeviceGroup_Protocol_t *msg, + bool encrypted + ); + +bool is_double(DeviceGroup_Protocol_t *msg); + +#ifdef __cplusplus +} +#endif + diff --git a/sync/Makefile b/sync/Makefile new file mode 100644 index 00000000..d4f8021e --- /dev/null +++ b/sync/Makefile @@ -0,0 +1,38 @@ +# Copyright 2017, pEp Foundation +# This file is part of pEpEngine +# This file may be used under the terms of the GNU General Public License version 3 +# see LICENSE.txt + +include ../default.conf + +.PHONY: all +all: .codegen + +# Currently not in use, kept for historic reasons +skeleton: .actions + +.codegen: .statemachines .actions + cp -f generated/*.* ../src + touch $@ + +.actions: devicegroup.fsm gen_actions.ysl2 fsm.yml2 functions.ysl2 + $(YML2_PROC) $(YML2_OPTS) -y gen_actions.ysl2 $< -o $@ + +.statemachines: devicegroup.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2 + $(YML2_PROC) $(YML2_OPTS) -y gen_statemachine.ysl2 $< -o $@ + +.PHONY: clean +clean: + rm -f *.xml *.xsl *.dot *.svg \ + $(patsubst generated/%,../src/%,$(wildcard generated/*.*)) \ + ../generated/* ../skeletons/* .statemachines .actions .codegen \ + generated/Makefile.protocols + +%.xml: %.fsm + $(YML2_PATH)/yml2c $< -o $@ + +%.dot: gen_dot.ysl2 devicegroup.fsm + $(YML2_PROC) $(YML2_OPTS) -y $^ + +%.svg: %.dot + dot -Tsvg -o $@ $< diff --git a/sync/devicegroup.fsm b/sync/devicegroup.fsm new file mode 100644 index 00000000..c9e83a41 --- /dev/null +++ b/sync/devicegroup.fsm @@ -0,0 +1,354 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// DeviceGroup protocol for p≡p + +// Copyleft (c) 2016, p≡p foundation + +// Written by Volker Birk + +include ./fsm.yml2 + +protocol DeviceGroup { + // all messages have a timestamp, time out and are removed after timeout + + broadcast sendBeacon; + broadcast sendGroupUpdate; + broadcast sendUpdateRequest; + unencrypted sendBeacon; + + fsm DeviceState filename=sync { + condition deviceGrouped(); + condition keyElectionWon(Identity partner); + condition sameIdentities(Identity a, Identity b); + condition sameKeyAndAddress(Identity a, Identity b); + + state InitState { + on Init { + if deviceGrouped() + go Grouped; + go Sole; + } + } + + state Sole end=1 { + on KeyGen { + do sendBeacon; + go SoleWaiting; + } + on CannotDecrypt { + do sendBeacon; + go SoleWaiting; + } + on Beacon(Identity partner){ + do sendHandshakeRequest(partner); + go SoleBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + do sendHandshakeRequest(partner); + go HandshakingSole(partner); + } + } + + // copy of sole state with a timeout to enable fast polling for a second + // TODO use more YSLT power here (substates ?) + state SoleWaiting timeout=60 { + on KeyGen { + do sendBeacon; + } + on CannotDecrypt { + do sendBeacon; + } + on Beacon(Identity partner){ + do sendHandshakeRequest(partner); + go SoleBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + do sendHandshakeRequest(partner); + go HandshakingSole(partner); + } + on Timeout go Sole; + } + + state SoleBeaconed timeout=600 (Identity expected) { + on KeyGen{ + do sendBeacon; + go Sole; + } + on CannotDecrypt{ + do sendBeacon; + go Sole; + } + on Beacon(Identity partner) { + do sendHandshakeRequest(partner); + go SoleBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + if sameIdentities(partner, expected) { + // do nothing, to avoid sending handshake request twice + } else { + do sendHandshakeRequest(partner); + } + go HandshakingSole(partner); + } + on Timeout go Sole; + } + + state HandshakingSole timeout=600 (Identity expected) { + on Init{ + if keyElectionWon(expected) { + do notifyInitFormGroup(expected); + } else { + do notifyInitAddOurDevice(expected); + } + } + on HandshakeRejected(Identity partner) { + do rejectHandshake(partner); + go Sole; + } + on HandshakeAccepted(Identity partner) { + if sameIdentities(partner, expected) { + do acceptHandshake(partner); + if keyElectionWon(partner) { + do makeGroup; + do sendGroupKeys(partner); + do renewUUID; + do notifyAcceptedGroupCreated(partner); + go Grouped; + } + go WaitForGroupKeysSole(partner); + } + go Sole; + } + on Cancel go Sole; + on GroupKeys(Identity partner, GroupKeys groupkeys) { + if keyElectionWon(expected) { + // not supposed to receive groupkeys - ignore + } else { + // UUID changes in between, so we can only check for same address and fpr + if sameKeyAndAddress(partner, expected) { + go WaitForAcceptSole(partner, groupkeys); + } + } + } + on Timeout { + do notifyTimeout(expected); + do sendBeacon; + go Sole; + } + } + + state WaitForGroupKeysSole timeout=600 (Identity expected) { + on GroupKeys(Identity partner, GroupKeys groupkeys) { + // UUID changes in between, so we can only check for same address and fpr + if sameKeyAndAddress(partner, expected) { + do storeGroupKeys(partner, groupkeys); + do sendGroupUpdate; + do renewUUID; + do notifyAcceptedDeviceAdded(partner); + go Grouped; + } + } + on Timeout { + do notifyTimeout(expected); + go Sole; + } + } + + state WaitForAcceptSole timeout=600 (Identity expected, GroupKeys groupkeys) { + on HandshakeRejected(Identity partner) { + do rejectHandshake(partner); + go Sole; + } + on HandshakeAccepted(Identity partner) { + // UUID changes in between, so we can only check for same address and fpr + if sameKeyAndAddress(partner, expected) { + do acceptHandshake(partner); + do storeGroupKeys(partner, groupkeys); + do sendGroupUpdate; + do renewUUID; + do notifyAcceptedDeviceAdded(partner); + go Grouped; + } + go Sole; + } + on Cancel go Sole; + on Timeout { + do notifyTimeout(expected); + go Sole; + } + } + + state Grouped end=1 { + on KeyGen + do sendGroupUpdate; + on CannotDecrypt { + do sendUpdateRequest; + do sendBeacon; + go GroupWaiting; + } + on UpdateRequest + do sendGroupUpdate; + on Beacon(Identity partner){ + do sendHandshakeRequest(partner); + go GroupedBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + do sendHandshakeRequest(partner); + go HandshakingGrouped(partner); + } + on GroupUpdate(Identity partner, IdentityList keys) + do storeGroupUpdate(partner, keys); + } + + // copy of grouped state, with a timeout to enable fast poling for a minut + state GroupWaiting timeout=60 { + on KeyGen + do sendGroupUpdate; + on CannotDecrypt { + do sendUpdateRequest; + do sendBeacon; + } + on UpdateRequest + do sendGroupUpdate; + on Beacon(Identity partner){ + do sendHandshakeRequest(partner); + go GroupedBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + do sendHandshakeRequest(partner); + go HandshakingGrouped(partner); + } + on GroupUpdate(Identity partner, IdentityList keys) + do storeGroupUpdate(partner, keys); + on Timeout go Grouped; + } + + state GroupedBeaconed timeout=600 (Identity expected){ + on KeyGen + do sendGroupUpdate; + on CannotDecrypt { + do sendUpdateRequest; + do sendBeacon; + } + on UpdateRequest + do sendGroupUpdate; + on Beacon(Identity partner){ + do sendHandshakeRequest(partner); + go GroupedBeaconed(partner); + } + on HandshakeRequest(Identity partner) { + if sameIdentities(partner, expected) { + // do nothing, to avoid sending handshake request twice + } else { + do sendHandshakeRequest(partner); + } + go HandshakingGrouped(partner); + } + on GroupUpdate(Identity partner, IdentityList keys) + do storeGroupUpdate(partner, keys); + on Timeout go Grouped; + } + + state HandshakingGrouped timeout=600 (Identity expected) { + // HandshakeRequest from same group are filtered in receive_sync_msg + on Init{ + if keyElectionWon(expected) { + do notifyInitAddOtherDevice(partner); + } else { + do notifyInitMoveOurDevice(partner); + } + } + on HandshakeRejected(Identity partner) { + do rejectHandshake(partner); // stores rejection of partner + do sendGroupUpdate; + go Grouped; + } + on HandshakeAccepted(Identity partner) { + do acceptHandshake(partner); + do sendGroupUpdate; + if keyElectionWon(partner) { + do sendGroupKeys(partner); + do notifyAcceptedDeviceAdded(partner); + go Grouped; + } + go WaitForGroupKeysGrouped(partner); + } + on Cancel go Grouped; + on GroupKeys(Identity partner, GroupKeys groupkeys) { + if keyElectionWon(expected) { + // not supposed to receive groupkeys - ignore + } else { + // UUID changes in between, so we can only check for same address and fpr + if sameKeyAndAddress(partner, expected) { + go WaitForAcceptGrouped(partner, groupkeys); + } + } + } + on GroupUpdate(Identity partner, IdentityList keys) { + do notifyOvertaken(partner); + do storeGroupUpdate(partner, keys); + go Grouped; + } + on Timeout { + do notifyTimeout(expected); + go Grouped; + } + } + + state WaitForGroupKeysGrouped timeout=600 (Identity expected) { + on GroupKeys(Identity partner, GroupKeys groupkeys) { + if sameIdentities(partner, expected) { + do storeGroupKeys(partner, groupkeys); + do sendGroupUpdate; + do renewUUID; + do notifyAcceptedDeviceMoved(partner); + go Grouped; + } + } + on GroupUpdate(Identity partner, IdentityList keys) { + do notifyOvertaken(partner); + do storeGroupUpdate(partner, keys); + go Grouped; + } + on Timeout { + do notifyTimeout(expected); + go Grouped; + } + } + + state WaitForAcceptGrouped timeout=600 (Identity expected, GroupKeys groupkeys) { + on HandshakeRejected(Identity partner) { + do rejectHandshake(partner); + do sendGroupUpdate; + go Grouped; + } + on HandshakeAccepted(Identity partner) { + if sameIdentities(partner, expected) { + do acceptHandshake(partner); + do storeGroupKeys(partner, groupkeys); + do sendGroupUpdate; + do renewUUID; + do notifyAcceptedDeviceMoved(partner); + } + go Grouped; + } + on Cancel go Grouped; + on GroupUpdate(Identity partner, IdentityList keys) { + do notifyOvertaken(partner); + do storeGroupUpdate(partner, keys); + go Grouped; + } + on Timeout { + do notifyTimeout(expected); + go Grouped; + } + } + + tag Init 1; + tag Beacon 2; + tag HandshakeRequest 3; + tag GroupKeys 4; + } +} + diff --git a/sync/fsm.yml2 b/sync/fsm.yml2 new file mode 100644 index 00000000..e75f6751 --- /dev/null +++ b/sync/fsm.yml2 @@ -0,0 +1,19 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// FSM Y language 1.0 + +// Copyleft (c) 2016, p≡p foundation + +// Written by Volker Birk + +decl protocol @name; +decl fsm @name; +decl state @name (timeout=0); +decl event @name, on is event; +decl transition @target, go is transition; +decl action @name, do is action; +decl condition @name, if is condition; +decl alternative, else is alternative; +decl interface @name; +decl tag @name (id); diff --git a/sync/functions.ysl2 b/sync/functions.ysl2 new file mode 100644 index 00000000..6ea721bf --- /dev/null +++ b/sync/functions.ysl2 @@ -0,0 +1,15 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// function library + +def "func:distinctName" { + param "nodes", "/.."; + choose { + when "not($nodes)" + result "/.."; + otherwise { + result "$nodes[1] | func:distinctName($nodes[position() > 1])[@name != $nodes[1]/@name]"; + } + } +} diff --git a/sync/gen_actions.ysl2 b/sync/gen_actions.ysl2 new file mode 100644 index 00000000..255766c4 --- /dev/null +++ b/sync/gen_actions.ysl2 @@ -0,0 +1,300 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// generate actions skeleton + +// Copyleft (c) 2016, p≡p foundation + +// Written by Volker Birk + +include yslt.yml2 + +tstylesheet { + include standardlib.ysl2 + include ./functions.ysl2 + + template "/protocol" { + apply "fsm", mode=send, 0; + apply "fsm", mode=other, 0; + } + + template "fsm", mode=send document "generated/{@filename}_send_actions.c", "text" { + const "name", "@name"; + const "filename", "@filename"; + || + // Send Actions for «@name» state machine + + #include + #include "pEp_internal.h" + #include "keymanagement.h" + #include "message.h" + #include "«@filename»_fsm.h" + #include "baseprotocol.h" + #include "map_asn1.h" + #include "../asn.1/DeviceGroup-Protocol.h" + #include "sync_impl.h" + || + for "func:distinctName(//action)" + if "substring(@name, 1, 4) = 'send'" + | #include "../asn.1/«substring(@name, 5, 255)».h" + | + for "func:distinctName(//action)" + if "substring(@name, 1, 4) = 'send'" + call "send_action" + with "action", ".", + with "fsm", "$name", + with "filename", "$filename"; + + || + + PEP_STATUS _notifyHandshake( + PEP_SESSION session, + Identity partner, + sync_handshake_signal signal + ); + || + + for "func:distinctName(//action)" + if "substring(@name, 1, 6) = 'notify'" + call "notify_action" + with "action", ".", + with "fsm", "$name", + with "filename", "$filename"; + } + + template "fsm", mode=other document "skeletons/{@filename}_actions.c", "text" { + const "name", "@name"; + const "filename", "@filename"; + || + // Actions for «@name» state machine + + #include + #include "pEp_internal.h" + #include "keymanagement.h" + #include "message.h" + #include "«@filename»_fsm.h" + #include "../asn.1/DeviceGroup-Protocol.h" + + || + for "func:distinctName(//action)" + if "substring(@name, 1, 4) != 'send'" + call "other_action" + with "action", ".", + with "fsm", "$name", + with "filename", "$filename"; + } + + function "paramcheck" { + param "partner"; + |> assert(session); + choose { + when "$partner" + || + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + || + otherwise + || + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + || + } + } + + function "other_action" { + param "action"; + param "fsm"; + param "filename", "'###'"; + + || + + // «$action/@name»() - + // + // params: + // session (in) session handle + // state (in) state the state machine is in + `` if "parm" | // partner (in) partner to communicate with + `` if "not(parm)" | // partner (in) (must be NULL) + // + // returns: + // PEP_STATUS_OK or any other value on error + + PEP_STATUS «$action/@name»( + PEP_SESSION session, + «$fsm»_state state, + Identity partner, + void *extra + ) + { + PEP_STATUS status = PEP_STATUS_OK; + + `` call "paramcheck" with "partner", "parm/partner"; + + // working code + + // free extra + return status; + + enomem: + status = PEP_OUT_OF_MEMORY; + error: + // free extra + return status; + } + + || + } + + function "send_action" { + param "action"; + param "fsm"; + param "filename", "'###'"; + const "name", "substring($action/@name, 5, 255)"; + const "lname", "concat(yml:lcase(substring($name, 1, 1)), substring($name, 2))"; + + || + + // «$action/@name»() - send «$name» message + // + // params: + // session (in) session handle + // state (in) state the state machine is in + `` if "parm" | // partner (in) partner to communicate with + `` if "not(parm)" | // partner (in) (must be NULL) + // + // returns: + // PEP_STATUS_OK or any other value on error + + PEP_STATUS «$action/@name»( + PEP_SESSION session, + «$fsm»_state state, + Identity partner, + void *extra + ) + { + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + `` if "$name='GroupKeys' or $name='GroupUpdate'" |> identity_list *kl = new_identity_list(NULL); + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_«$lname»); + if (!msg) + goto enomem; + || + choose { + when "$name='GroupKeys' or $name='GroupUpdate'" { + | + |> status = _own_identities_retrieve(session, &kl, PEP_idf_not_for_sync); + |> if (status != PEP_STATUS_OK) + |>> goto error; + |> if (IdentityList_from_identity_list(kl, &msg->payload.choice.«$lname».ownIdentities) == NULL) + |>> goto enomem; + } + } + choose { + when "$name='GroupKeys' or $name='HandshakeRequest'" { + | + |> msg->payload.choice.«$lname».partner_id = + |> OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + |> partner->user_id, -1); + |> if (partner->user_id && !msg->payload.choice.«$lname».partner_id) + |> goto enomem; + | + |> char *devgrp = NULL; + |> status = get_device_group(session, &devgrp); + |> if (status == PEP_STATUS_OK && devgrp && devgrp[0]) + |> msg->payload.choice.«$lname».group_id = + |> OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + |> devgrp, -1); + |> free(devgrp); + |> if (devgrp && !msg->payload.choice.«$lname».partner_id) + |> goto enomem; + } + } + || + + || + choose { + when "count(/protocol/unencrypted/*[name()=$action/@name]) = 0" + |> bool encrypted = true; + otherwise + |> bool encrypted = false; + } + choose { + when "count(/protocol/broadcast/*[name()=$action/@name]) = 0" + |> status = unicast_msg(session, partner, state, msg, encrypted); + otherwise + |> status = multicast_self_msg(session, state, msg, encrypted); + } + || + if (status != PEP_STATUS_OK) + goto error; + + `` if "$name='GroupKeys' or $name='GroupUpdate'" |> free_identity_list(kl); + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + + enomem: + status = PEP_OUT_OF_MEMORY; + error: + free_DeviceGroup_Protocol_msg(msg); + `` if "$name='GroupKeys'" |> free_identity_list(kl); + return status; + } + + || + } + + function "UnCamelUp" { + param "text"; + const "tokens", "str:tokenize($text, '')"; + + for "$tokens" { + choose { + when "contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ',.)" > _«.» + otherwise value "yml:ucase(.)"; + } + } + } + + function "notify_action" { + param "action"; + param "fsm"; + param "filename", "'###'"; + const "name", "substring($action/@name, 7, 255)"; + const "uname" call "UnCamelUp" with "text", "$name"; + || + + // «$action/@name»() - notify «$name» to app + // + // params: + // session (in) session handle + // state (in) state the state machine is in + // partner (in) partner to communicate with + // + // returns: + // PEP_STATUS_OK or any other value on error + + PEP_STATUS «$action/@name»( + PEP_SESSION session, + «$fsm»_state state, + Identity partner, + void *extra + ) + { + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY«$uname»); + } + + || + } +} + diff --git a/sync/gen_dot.ysl2 b/sync/gen_dot.ysl2 new file mode 100644 index 00000000..76b2219b --- /dev/null +++ b/sync/gen_dot.ysl2 @@ -0,0 +1,42 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +include yslt.yml2 + +tstylesheet { + template "protocol/fsm" document "{@filename}.dot", "text" + || + digraph finite_state_machine { + rankdir=LR; + node [shape = doublecircle]; + `apply "state[@end='1']" mode=end`; + node [shape = circle]; + + `` apply "state" mode=do + } + || + + template "state", mode=end > «@name» + template "state", mode=do apply "event", 0 with "state", "@name"; + + template "event" { + param "state"; + const "transitions", "transition|descendant::condition/transition|descendant::alternative/transition"; + choose { + when "count($transitions) > 0" + apply "$transitions", 0 + with "state", "$state", with "event", "@name"; + otherwise + if "@name != 'Init'" + | «$state» -> «$state» [ label="«@name»" ]; + } + } + + template "transition" { + param "state"; + param "event"; + + | «$state» -> «@target» [ label ="«$event»" ]; + } +} + diff --git a/sync/gen_statemachine.ysl2 b/sync/gen_statemachine.ysl2 new file mode 100644 index 00000000..78df75ff --- /dev/null +++ b/sync/gen_statemachine.ysl2 @@ -0,0 +1,415 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +// generate state machine code + +// Copyleft (c) 2016, p≡p foundation + +// Written by Volker Birk + +include yslt.yml2 + +tstylesheet { + include standardlib.ysl2 + include ./functions.ysl2 + + template "/protocol" { + document "generated/Makefile.protocols", "text" + apply "fsm", 0, mode="make"; + apply "fsm", 0, mode=gen; + } + + template "fsm", mode=make + || + «@filename»_fsm.c: ../sync/devicegroup.fsm + \tmake -C ../«@filename» + || + + template "fsm", mode=gen { + document "generated/{@filename}_fsm.h", "text" { + || + #pragma once + + // state machine for «@name» + + #include "message_api.h" + + #ifdef __cplusplus + extern "C" { + #endif + + // types + + typedef pEp_identity * Identity; + typedef stringlist_t * Stringlist; + + // error values + + typedef enum _fsm_error { + // these error values are corresponding to + // PEP_SYNC_STATEMACHINE_ERROR - value + invalid_state = -2, + invalid_event = -3, + invalid_condition = -4, + invalid_action = -5, + + // out of memory condition + invalid_out_of_memory = -128 + } fsm_error; + + // conditions + + `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`); + + // states + + typedef enum _«@name»_state { + // error values also in this namespace + «@name»_state_invalid_state = (int) invalid_state, + «@name»_state_invalid_event = (int) invalid_event, + «@name»_state_invalid_condition = (int) invalid_condition, + «@name»_state_invalid_action = (int) invalid_action, + «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory, + + «@name»_state_NONE = 0, + `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , ` + } «@name»_state; + + // events + + typedef enum _«@name»_event { + «@name»_event_NONE = 0, + || + for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" { + const "name", "@name"; + |> «$name» = «/protocol/fsm/tag[@name=$name]/@id», + } + for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])" + |> «@name»`if "position()!=last()" > , ` + || + } «@name»_event; + + // actions + + `` const "name", "@name" + `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra); + + // event injector + + PEP_STATUS inject_DeviceState_event( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra); + + // message receiver + + PEP_STATUS receive_DeviceState_msg( + PEP_SESSION session, + message *src, + PEP_rating rating, + stringlist_t *keylist + ); + + // state machine + + «@name»_state fsm_«@name»( + PEP_SESSION session, + «@name»_state state, + «@name»_event event, + Identity partner, + void *extra, + time_t *timeout + ); + + // driver + + DYNAMIC_API PEP_STATUS fsm_«@name»_inject( + PEP_SESSION session, + «@name»_event event, + Identity partner, + void *extra, + time_t *timeout + ); + + #ifdef __cplusplus + } + #endif + + || + } + document "generated/{@filename}_driver.c", "text" + || + // Driver for «@name» state machine + + #include + #include "pEp_internal.h" + + + DYNAMIC_API PEP_STATUS fsm_«@name»_inject( + PEP_SESSION session, + «@name»_event event, + Identity partner, + void *extra, + time_t *timeout + ) + { + assert(session); + if (!session) + return PEP_ILLEGAL_VALUE; + + while(true) + { + «@name»_state new_state = fsm_«@name»(session, + session->«@filename»_state, event, partner, extra, timeout); + + if (new_state == «@name»_state_invalid_out_of_memory) + return PEP_OUT_OF_MEMORY; + + if (new_state < 0) + return PEP_SYNC_STATEMACHINE_ERROR - new_state; + + if (new_state == session->«@filename»_state) + break; + + event = Init; + extra = NULL; + session->«@filename»_state = new_state; + } + + return PEP_STATUS_OK; + } + + || + document "generated/{@filename}_fsm.c", "text" + || + #include "pEp_internal.h" + #include "«@filename»_fsm.h" + #include "«@filename»_impl.h" + + // local definitions for «@name»'s state machine + + `` apply "state", 0 mode="declStatePayload" + + // state machine for «@name» + + «@name»_state fsm_«@name»( + PEP_SESSION session, + «@name»_state state, + «@name»_event event, + Identity partner, + void *extra, + time_t *timeout + ) + { + PEP_STATUS status = PEP_STATUS_OK; + + switch (state) { + `` apply "state", 2 + default: + return («@name»_state) invalid_state; + } + + return state; + } + + || + } + + template "state" { + || + case «@name»: + { + DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»") + || + + if "count(parm) > 0" + || + assert(session->sync_state_payload); + if(!session->sync_state_payload) return («../@name»_state) invalid_state; + `` apply "parm", 1 mode="unpackStatePayloadParm" with "stateName", "@name" + || + + || + switch (event) { + || + + if "not(event[@name='Init'])" + || + case Init: + DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") + *timeout = «@timeout»; + break; + || + + apply "event", 2; + + || + default: + return («../@name»_state) invalid_event; + } + break; + } + || + } + + function "pEp_type" { + param "type"; + + choose { + when "$type = 'Identity'" > Identity + when "$type = 'IdentityList'" > identity_list* + when "$type = 'GroupKeys'" > group_keys_extra_t* + otherwise value "$type"; + } + } + + function "pEp_type_op_radix" { + param "type"; + + choose { + when "$type = 'Identity'" > identity + when "$type = 'IdentityList'" > identity_list + when "$type = 'GroupKeys'" > group_keys_extra + otherwise call "pEp_type" with "type", "$type"; + } + } + + template "parm" mode="unpackStatePayloadParm" + { + param "stateName"; + const "pEpType" call "pEp_type" with "type","name(*[1])"; + | «$pEpType» «name(*[2])» = ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»; + } + + template "state" mode="declStatePayload" if "count(parm) > 0" + || + typedef struct _«@name»_state_payload { + `` apply "parm", 1 mode="declStatePayloadParm" + } «@name»_state_payload_t; + + || + + template "parm" mode="declStatePayloadParm" { + const "pEpType" call "pEp_type" with "type","name(*[1])"; + | «$pEpType» «name(*[2])»; + } + + template "event" { + || + case «@name»: + { + DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»") + `` if "@name='Init'" |> *timeout = «../@timeout»; + || + + if "count(parm) > 1" { + // TODO get ride of void *extra, pass per-event struct incl all params. + const "extrapEpType" call "pEp_type" with "type","name(parm[2]/*[1])"; + const "extraArgName","name(parm[2]/*[2])"; + |> «$extrapEpType» «$extraArgName» = («$extrapEpType»)extra; + } + + || + `` apply "action|transition|condition"; + `` if "name(*[position()=last()]) != 'transition'" |> break; + } + || + } + + template "action" { + | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»") + indent(0); + > status = «@name»(session, state, + choose { + when "parm" > «name(parm/*)» + otherwise > NULL + } + choose { + when "count(parm) > 1" > , «name(parm[2]/*)» + otherwise > , NULL + } + > );\n + | if (status == PEP_OUT_OF_MEMORY) + |> return (int) invalid_out_of_memory; + | if (status != PEP_STATUS_OK) + |> return (int) invalid_action; + } + + template "condition" { + | { + |> int cond_result = «@name»(session`apply "parm", 0`); + |> #ifndef NDEBUG + |> char resstr[11] = {0,}; + |> snprintf(resstr,10,"result=%d",cond_result); + |> #endif + |> DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr) + |> if (cond_result < 0) + |>> return cond_result; + |> if (cond_result) { + apply "action|transition|condition"; + |> } + const "alternative", "./following-sibling::*[position()=1][name(.)='alternative']"; + if "$alternative" { + |> else { + apply "$alternative/action|$alternative/transition|$alternative/condition"; + |> } + } + | } + } + + template "parm" choose { + when "count(*) = 1" + > , «name(*)» + otherwise + > , «name(*[1])» «name(*[2])» + } + + template "transition"{ + const "stateparm", "ancestor::state/child::parm"; + if "count($stateparm) > 0" { + || + assert(session->sync_state_payload); + if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_state; + `` apply "$stateparm", 0 mode="freeStatePayloadParm" with "stateName", "ancestor::state/@name" + free(session->sync_state_payload); + session->sync_state_payload = NULL; + || + } + if "count(parm) > 0" { + const "nextstatename", "@target"; + const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm"; + if "count(parm) != count($nextstateparm)" + error > different state parameters and transition parameters count state=«ancestor::state/@name», event=«ancestor::event/@name» target=«@target» + || + session->sync_state_payload = malloc(sizeof(«$nextstatename»_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_out_of_memory; + || + apply "$nextstateparm", 0 mode="dupStatePayloadParm" { + with "stateName", "$nextstatename"; + with "transitionParms", "parm"; + } + } + | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»") + | return «@target»; + } + + template "parm" mode="freeStatePayloadParm" + { + param "stateName"; + const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; + | free_«$pEpTypeOpRadix»(((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»); + } + + template "parm" mode="dupStatePayloadParm" + { + param "stateName"; + param "transitionParms"; + const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; + const "pos", "position()"; + | ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])» = + | «$pEpTypeOpRadix»_dup(«name($transitionParms[$pos]/*)»); + } +} + diff --git a/sync/generated/README b/sync/generated/README new file mode 100644 index 00000000..ace3875e --- /dev/null +++ b/sync/generated/README @@ -0,0 +1,11 @@ +Code is generated here before beeing copied to /src during build process. + +This code is intended to be commited and reviewed, while the original files +in src/ aren't tracked in mercurial (.hgignore). + +Generated code must be generated out of source code systematically at build, +since generation could be influenced by build environment and parameters. + +Depending on build host, version control tool or unharchiving tool, generated +files timestamp may prevent re-generation. They must then be excluded from repo. + diff --git a/sync/generated/sync_driver.c b/sync/generated/sync_driver.c new file mode 100644 index 00000000..4f652177 --- /dev/null +++ b/sync/generated/sync_driver.c @@ -0,0 +1,40 @@ +// Driver for DeviceState state machine + +#include +#include "pEp_internal.h" + + +DYNAMIC_API PEP_STATUS fsm_DeviceState_inject( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra, + time_t *timeout + ) +{ + assert(session); + if (!session) + return PEP_ILLEGAL_VALUE; + + while(true) + { + DeviceState_state new_state = fsm_DeviceState(session, + session->sync_state, event, partner, extra, timeout); + + if (new_state == DeviceState_state_invalid_out_of_memory) + return PEP_OUT_OF_MEMORY; + + if (new_state < 0) + return PEP_SYNC_STATEMACHINE_ERROR - new_state; + + if (new_state == session->sync_state) + break; + + event = Init; + extra = NULL; + session->sync_state = new_state; + } + + return PEP_STATUS_OK; +} + diff --git a/sync/generated/sync_fsm.c b/sync/generated/sync_fsm.c new file mode 100644 index 00000000..2d58b334 --- /dev/null +++ b/sync/generated/sync_fsm.c @@ -0,0 +1,1610 @@ +#include "pEp_internal.h" +#include "sync_fsm.h" +#include "sync_impl.h" + +// local definitions for DeviceState's state machine + +typedef struct _SoleBeaconed_state_payload { + Identity expected; +} SoleBeaconed_state_payload_t; + +typedef struct _HandshakingSole_state_payload { + Identity expected; +} HandshakingSole_state_payload_t; + +typedef struct _WaitForGroupKeysSole_state_payload { + Identity expected; +} WaitForGroupKeysSole_state_payload_t; + +typedef struct _WaitForAcceptSole_state_payload { + Identity expected; + group_keys_extra_t* groupkeys; +} WaitForAcceptSole_state_payload_t; + +typedef struct _GroupedBeaconed_state_payload { + Identity expected; +} GroupedBeaconed_state_payload_t; + +typedef struct _HandshakingGrouped_state_payload { + Identity expected; +} HandshakingGrouped_state_payload_t; + +typedef struct _WaitForGroupKeysGrouped_state_payload { + Identity expected; +} WaitForGroupKeysGrouped_state_payload_t; + +typedef struct _WaitForAcceptGrouped_state_payload { + Identity expected; + group_keys_extra_t* groupkeys; +} WaitForAcceptGrouped_state_payload_t; + + +// state machine for DeviceState + +DeviceState_state fsm_DeviceState( + PEP_SESSION session, + DeviceState_state state, + DeviceState_event event, + Identity partner, + void *extra, + time_t *timeout + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + switch (state) { + case InitState: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=InitState") + switch (event) { + case Init: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=InitState", "event=Init") + *timeout = 0; + { + int cond_result = deviceGrouped(session); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=InitState, event=Init, condition=deviceGrouped", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM transition", "sync_fsm.c, state=InitState, event=Init", "target=Grouped") + return Grouped; + } + } + DEBUG_LOG("FSM transition", "sync_fsm.c, state=InitState, event=Init", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case Sole: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Sole") + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=Init") + *timeout = 0; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Sole, event=KeyGen", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=KeyGen", "target=SoleWaiting") + return SoleWaiting; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Sole, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=CannotDecrypt", "target=SoleWaiting") + return SoleWaiting; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Sole, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=Beacon", "target=SoleBeaconed") + return SoleBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=HandshakeRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Sole, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=HandshakeRequest", "target=HandshakingSole") + return HandshakingSole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case SoleWaiting: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleWaiting") + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Init") + *timeout = 60; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=KeyGen", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Beacon", "target=SoleBeaconed") + return SoleBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=HandshakeRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "target=HandshakingSole") + return HandshakingSole; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Timeout") + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Timeout", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case SoleBeaconed: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleBeaconed") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Init") + *timeout = 600; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleBeaconed, event=KeyGen", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=KeyGen", "target=Sole") + return Sole; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleBeaconed, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=CannotDecrypt", "target=Sole") + return Sole; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleBeaconed, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=Beacon", "target=SoleBeaconed") + return SoleBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=HandshakeRequest") + { + int cond_result = sameIdentities(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + } + else { + DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest", "target=HandshakingSole") + return HandshakingSole; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Timeout") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=Timeout", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case HandshakingSole: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=HandshakingSole") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Init") + *timeout = 600; + { + int cond_result = keyElectionWon(session, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=Init, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitFormGroup") + status = notifyInitFormGroup(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + else { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitAddOurDevice") + status = notifyInitAddOurDevice(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + } + break; + } + case HandshakeRejected: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=HandshakeRejected") + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeRejected", "action=rejectHandshake") + status = rejectHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeRejected", "target=Sole") + return Sole; + } + case HandshakeAccepted: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=HandshakeAccepted") + { + int cond_result = sameIdentities(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted, condition=sameIdentities", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=acceptHandshake") + status = acceptHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + { + int cond_result = keyElectionWon(session, partner); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=makeGroup") + status = makeGroup(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=sendGroupKeys") + status = sendGroupKeys(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=renewUUID") + status = renewUUID(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=notifyAcceptedGroupCreated") + status = notifyAcceptedGroupCreated(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=Grouped") + return Grouped; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(WaitForGroupKeysSole_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=WaitForGroupKeysSole") + return WaitForGroupKeysSole; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=Sole") + return Sole; + } + case Cancel: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Cancel") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=Cancel", "target=Sole") + return Sole; + } + case GroupKeys: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=GroupKeys") + group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra; + { + int cond_result = keyElectionWon(session, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + } + else { + { + int cond_result = sameKeyAndAddress(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=sameKeyAndAddress", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(WaitForAcceptSole_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys = + group_keys_extra_dup(groupkeys); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys", "target=WaitForAcceptSole") + return WaitForAcceptSole; + } + } + } + } + break; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Timeout", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=Timeout", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case WaitForGroupKeysSole: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForGroupKeysSole") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=Init") + *timeout = 600; + break; + case GroupKeys: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=GroupKeys") + group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra; + { + int cond_result = sameKeyAndAddress(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys, condition=sameKeyAndAddress", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=storeGroupKeys") + status = storeGroupKeys(session, state, partner, groupkeys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=renewUUID") + status = renewUUID(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=notifyAcceptedDeviceAdded") + status = notifyAcceptedDeviceAdded(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "target=Grouped") + return Grouped; + } + } + break; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysSole, event=Timeout", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case WaitForAcceptSole: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForAcceptSole") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected; + group_keys_extra_t* groupkeys = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Init") + *timeout = 600; + break; + case HandshakeRejected: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=HandshakeRejected") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeRejected", "action=rejectHandshake") + status = rejectHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeRejected", "target=Sole") + return Sole; + } + case HandshakeAccepted: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=HandshakeAccepted") + { + int cond_result = sameKeyAndAddress(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted, condition=sameKeyAndAddress", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=acceptHandshake") + status = acceptHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=storeGroupKeys") + status = storeGroupKeys(session, state, partner, groupkeys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=renewUUID") + status = renewUUID(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=notifyAcceptedDeviceAdded") + status = notifyAcceptedDeviceAdded(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "target=Grouped") + return Grouped; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "target=Sole") + return Sole; + } + case Cancel: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Cancel") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=Cancel", "target=Sole") + return Sole; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=Timeout", "target=Sole") + return Sole; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case Grouped: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Grouped") + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=Init") + *timeout = 0; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=KeyGen", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "action=sendUpdateRequest") + status = sendUpdateRequest(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "target=GroupWaiting") + return GroupWaiting; + } + case UpdateRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=UpdateRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=UpdateRequest", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=Beacon", "target=GroupedBeaconed") + return GroupedBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=HandshakeRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=HandshakeRequest", "target=HandshakingGrouped") + return HandshakingGrouped; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case GroupWaiting: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=GroupWaiting") + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Init") + *timeout = 60; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=KeyGen", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=CannotDecrypt", "action=sendUpdateRequest") + status = sendUpdateRequest(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case UpdateRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=UpdateRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=UpdateRequest", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=Beacon", "target=GroupedBeaconed") + return GroupedBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=HandshakeRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=HandshakeRequest", "target=HandshakingGrouped") + return HandshakingGrouped; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Timeout") + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=Timeout", "target=Grouped") + return Grouped; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case GroupedBeaconed: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=GroupedBeaconed") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Init") + *timeout = 600; + break; + case KeyGen: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=KeyGen") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=KeyGen", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case CannotDecrypt: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=CannotDecrypt") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=CannotDecrypt", "action=sendUpdateRequest") + status = sendUpdateRequest(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=CannotDecrypt", "action=sendBeacon") + status = sendBeacon(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case UpdateRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=UpdateRequest") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=UpdateRequest", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Beacon: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Beacon") + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=Beacon", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=Beacon", "target=GroupedBeaconed") + return GroupedBeaconed; + } + case HandshakeRequest: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=HandshakeRequest") + { + int cond_result = sameIdentities(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + } + else { + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest", "action=sendHandshakeRequest") + status = sendHandshakeRequest(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest", "target=HandshakingGrouped") + return HandshakingGrouped; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + break; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Timeout") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=Timeout", "target=Grouped") + return Grouped; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case HandshakingGrouped: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=HandshakingGrouped") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=Init") + *timeout = 600; + { + int cond_result = keyElectionWon(session, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=Init, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Init", "action=notifyInitAddOtherDevice") + status = notifyInitAddOtherDevice(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + else { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Init", "action=notifyInitMoveOurDevice") + status = notifyInitMoveOurDevice(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + } + break; + } + case HandshakeRejected: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=HandshakeRejected") + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeRejected", "action=rejectHandshake") + status = rejectHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeRejected", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeRejected", "target=Grouped") + return Grouped; + } + case HandshakeAccepted: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=HandshakeAccepted") + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=acceptHandshake") + status = acceptHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + { + int cond_result = keyElectionWon(session, partner); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=sendGroupKeys") + status = sendGroupKeys(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=notifyAcceptedDeviceAdded") + status = notifyAcceptedDeviceAdded(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "target=Grouped") + return Grouped; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(WaitForGroupKeysGrouped_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "target=WaitForGroupKeysGrouped") + return WaitForGroupKeysGrouped; + } + case Cancel: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=Cancel") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=Cancel", "target=Grouped") + return Grouped; + } + case GroupKeys: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=GroupKeys") + group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra; + { + int cond_result = keyElectionWon(session, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys, condition=keyElectionWon", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + } + else { + { + int cond_result = sameKeyAndAddress(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys, condition=sameKeyAndAddress", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + session->sync_state_payload = malloc(sizeof(WaitForAcceptGrouped_state_payload_t)); + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory; + ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected = + identity_dup(partner); + ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys = + group_keys_extra_dup(groupkeys); + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys", "target=WaitForAcceptGrouped") + return WaitForAcceptGrouped; + } + } + } + } + break; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "action=notifyOvertaken") + status = notifyOvertaken(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "target=Grouped") + return Grouped; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=Timeout", "target=Grouped") + return Grouped; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case WaitForGroupKeysGrouped: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForGroupKeysGrouped") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=Init") + *timeout = 600; + break; + case GroupKeys: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=GroupKeys") + group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra; + { + int cond_result = sameIdentities(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys, condition=sameIdentities", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=storeGroupKeys") + status = storeGroupKeys(session, state, partner, groupkeys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=renewUUID") + status = renewUUID(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=notifyAcceptedDeviceMoved") + status = notifyAcceptedDeviceMoved(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "target=Grouped") + return Grouped; + } + } + break; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "action=notifyOvertaken") + status = notifyOvertaken(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "target=Grouped") + return Grouped; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=Timeout", "target=Grouped") + return Grouped; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + case WaitForAcceptGrouped: + { + DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForAcceptGrouped") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + Identity expected = ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected; + group_keys_extra_t* groupkeys = ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys; + switch (event) { + case Init: + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Init") + *timeout = 600; + break; + case HandshakeRejected: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=HandshakeRejected") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "action=rejectHandshake") + status = rejectHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "target=Grouped") + return Grouped; + } + case HandshakeAccepted: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=HandshakeAccepted") + { + int cond_result = sameIdentities(session, partner, expected); + #ifndef NDEBUG + char resstr[11] = {0,}; + snprintf(resstr,10,"result=%d",cond_result); + #endif + DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted, condition=sameIdentities", resstr) + if (cond_result < 0) + return cond_result; + if (cond_result) { + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=acceptHandshake") + status = acceptHandshake(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=storeGroupKeys") + status = storeGroupKeys(session, state, partner, groupkeys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=sendGroupUpdate") + status = sendGroupUpdate(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=renewUUID") + status = renewUUID(session, state, NULL, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=notifyAcceptedDeviceMoved") + status = notifyAcceptedDeviceMoved(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + } + } + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "target=Grouped") + return Grouped; + } + case Cancel: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Cancel") + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=Cancel", "target=Grouped") + return Grouped; + } + case GroupUpdate: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=GroupUpdate") + identity_list* keys = (identity_list*)extra; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "action=notifyOvertaken") + status = notifyOvertaken(session, state, partner, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "action=storeGroupUpdate") + status = storeGroupUpdate(session, state, partner, keys); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "target=Grouped") + return Grouped; + } + case Timeout: + { + DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Timeout") + DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=Timeout", "action=notifyTimeout") + status = notifyTimeout(session, state, expected, NULL); + if (status == PEP_OUT_OF_MEMORY) + return (int) invalid_out_of_memory; + if (status != PEP_STATUS_OK) + return (int) invalid_action; + assert(session->sync_state_payload); + if(!session->sync_state_payload) return (DeviceState_state) invalid_state; + free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected); + free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys); + free(session->sync_state_payload); + session->sync_state_payload = NULL; + DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=Timeout", "target=Grouped") + return Grouped; + } + default: + return (DeviceState_state) invalid_event; + } + break; + } + default: + return (DeviceState_state) invalid_state; + } + + return state; +} + diff --git a/sync/generated/sync_fsm.h b/sync/generated/sync_fsm.h new file mode 100644 index 00000000..d42e8ca9 --- /dev/null +++ b/sync/generated/sync_fsm.h @@ -0,0 +1,145 @@ +#pragma once + +// state machine for DeviceState + +#include "message_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// types + +typedef pEp_identity * Identity; +typedef stringlist_t * Stringlist; + +// error values + +typedef enum _fsm_error { + // these error values are corresponding to + // PEP_SYNC_STATEMACHINE_ERROR - value + invalid_state = -2, + invalid_event = -3, + invalid_condition = -4, + invalid_action = -5, + + // out of memory condition + invalid_out_of_memory = -128 +} fsm_error; + +// conditions + +int deviceGrouped(PEP_SESSION session); +int keyElectionWon(PEP_SESSION session, Identity partner); +int sameIdentities(PEP_SESSION session, Identity a, Identity b); +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b); + +// states + +typedef enum _DeviceState_state { + // error values also in this namespace + DeviceState_state_invalid_state = (int) invalid_state, + DeviceState_state_invalid_event = (int) invalid_event, + DeviceState_state_invalid_condition = (int) invalid_condition, + DeviceState_state_invalid_action = (int) invalid_action, + DeviceState_state_invalid_out_of_memory = (int) invalid_out_of_memory, + + DeviceState_state_NONE = 0, + InitState, + Sole, + SoleWaiting, + SoleBeaconed, + HandshakingSole, + WaitForGroupKeysSole, + WaitForAcceptSole, + Grouped, + GroupWaiting, + GroupedBeaconed, + HandshakingGrouped, + WaitForGroupKeysGrouped, + WaitForAcceptGrouped +} DeviceState_state; + +// events + +typedef enum _DeviceState_event { + DeviceState_event_NONE = 0, + Init = 1, + Beacon = 2, + HandshakeRequest = 3, + GroupKeys = 4, + KeyGen, + CannotDecrypt, + Timeout, + HandshakeRejected, + HandshakeAccepted, + Cancel, + UpdateRequest, + GroupUpdate +} DeviceState_event; + +// actions + +PEP_STATUS sendBeacon(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS sendHandshakeRequest(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyInitFormGroup(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyInitAddOurDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS rejectHandshake(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS acceptHandshake(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS makeGroup(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS sendGroupKeys(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS renewUUID(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyAcceptedGroupCreated(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyTimeout(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS storeGroupKeys(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS sendGroupUpdate(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyAcceptedDeviceAdded(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS sendUpdateRequest(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS storeGroupUpdate(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyInitAddOtherDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyInitMoveOurDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyOvertaken(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); +PEP_STATUS notifyAcceptedDeviceMoved(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra); + +// event injector + +PEP_STATUS inject_DeviceState_event( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra); + +// message receiver + +PEP_STATUS receive_DeviceState_msg( + PEP_SESSION session, + message *src, + PEP_rating rating, + stringlist_t *keylist + ); + +// state machine + +DeviceState_state fsm_DeviceState( + PEP_SESSION session, + DeviceState_state state, + DeviceState_event event, + Identity partner, + void *extra, + time_t *timeout + ); + +// driver + +DYNAMIC_API PEP_STATUS fsm_DeviceState_inject( + PEP_SESSION session, + DeviceState_event event, + Identity partner, + void *extra, + time_t *timeout + ); + +#ifdef __cplusplus +} +#endif + diff --git a/sync/generated/sync_send_actions.c b/sync/generated/sync_send_actions.c new file mode 100644 index 00000000..4ac1c1af --- /dev/null +++ b/sync/generated/sync_send_actions.c @@ -0,0 +1,521 @@ +// Send Actions for DeviceState state machine + +#include +#include "pEp_internal.h" +#include "keymanagement.h" +#include "message.h" +#include "sync_fsm.h" +#include "baseprotocol.h" +#include "map_asn1.h" +#include "../asn.1/DeviceGroup-Protocol.h" +#include "sync_impl.h" +#include "../asn.1/Beacon.h" +#include "../asn.1/HandshakeRequest.h" +#include "../asn.1/GroupKeys.h" +#include "../asn.1/GroupUpdate.h" +#include "../asn.1/UpdateRequest.h" + + +// sendBeacon() - send Beacon message +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) (must be NULL) +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS sendBeacon( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_beacon); + if (!msg) + goto enomem; + + bool encrypted = false; + status = multicast_self_msg(session, state, msg, encrypted); + if (status != PEP_STATUS_OK) + goto error; + + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_DeviceGroup_Protocol_msg(msg); + return status; +} + + +// sendHandshakeRequest() - send HandshakeRequest message +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS sendHandshakeRequest( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_handshakeRequest); + if (!msg) + goto enomem; + + msg->payload.choice.handshakeRequest.partner_id = + OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + partner->user_id, -1); + if (partner->user_id && !msg->payload.choice.handshakeRequest.partner_id) + goto enomem; + + char *devgrp = NULL; + status = get_device_group(session, &devgrp); + if (status == PEP_STATUS_OK && devgrp && devgrp[0]) + msg->payload.choice.handshakeRequest.group_id = + OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + devgrp, -1); + free(devgrp); + if (devgrp && !msg->payload.choice.handshakeRequest.partner_id) + goto enomem; + + bool encrypted = true; + status = unicast_msg(session, partner, state, msg, encrypted); + if (status != PEP_STATUS_OK) + goto error; + + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_DeviceGroup_Protocol_msg(msg); + return status; +} + + +// sendGroupKeys() - send GroupKeys message +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS sendGroupKeys( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + identity_list *kl = new_identity_list(NULL); + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_groupKeys); + if (!msg) + goto enomem; + + status = _own_identities_retrieve(session, &kl, PEP_idf_not_for_sync); + if (status != PEP_STATUS_OK) + goto error; + if (IdentityList_from_identity_list(kl, &msg->payload.choice.groupKeys.ownIdentities) == NULL) + goto enomem; + + msg->payload.choice.groupKeys.partner_id = + OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + partner->user_id, -1); + if (partner->user_id && !msg->payload.choice.groupKeys.partner_id) + goto enomem; + + char *devgrp = NULL; + status = get_device_group(session, &devgrp); + if (status == PEP_STATUS_OK && devgrp && devgrp[0]) + msg->payload.choice.groupKeys.group_id = + OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String, + devgrp, -1); + free(devgrp); + if (devgrp && !msg->payload.choice.groupKeys.partner_id) + goto enomem; + + bool encrypted = true; + status = unicast_msg(session, partner, state, msg, encrypted); + if (status != PEP_STATUS_OK) + goto error; + + free_identity_list(kl); + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_DeviceGroup_Protocol_msg(msg); + free_identity_list(kl); + return status; +} + + +// sendGroupUpdate() - send GroupUpdate message +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) (must be NULL) +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS sendGroupUpdate( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + identity_list *kl = new_identity_list(NULL); + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_groupUpdate); + if (!msg) + goto enomem; + + status = _own_identities_retrieve(session, &kl, PEP_idf_not_for_sync); + if (status != PEP_STATUS_OK) + goto error; + if (IdentityList_from_identity_list(kl, &msg->payload.choice.groupUpdate.ownIdentities) == NULL) + goto enomem; + + bool encrypted = true; + status = multicast_self_msg(session, state, msg, encrypted); + if (status != PEP_STATUS_OK) + goto error; + + free_identity_list(kl); + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_DeviceGroup_Protocol_msg(msg); + return status; +} + + +// sendUpdateRequest() - send UpdateRequest message +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) (must be NULL) +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS sendUpdateRequest( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + if (!(session && state)) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_updateRequest); + if (!msg) + goto enomem; + + bool encrypted = true; + status = multicast_self_msg(session, state, msg, encrypted); + if (status != PEP_STATUS_OK) + goto error; + + free_DeviceGroup_Protocol_msg(msg); + return PEP_STATUS_OK; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + free_DeviceGroup_Protocol_msg(msg); + return status; +} + + +PEP_STATUS _notifyHandshake( + PEP_SESSION session, + Identity partner, + sync_handshake_signal signal + ); + +// notifyInitFormGroup() - notify InitFormGroup to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitFormGroup( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_FORM_GROUP); +} + + +// notifyInitAddOurDevice() - notify InitAddOurDevice to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitAddOurDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_ADD_OUR_DEVICE); +} + + +// notifyAcceptedGroupCreated() - notify AcceptedGroupCreated to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedGroupCreated( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_ACCEPTED_GROUP_CREATED); +} + + +// notifyTimeout() - notify Timeout to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyTimeout( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_TIMEOUT); +} + + +// notifyAcceptedDeviceAdded() - notify AcceptedDeviceAdded to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedDeviceAdded( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED); +} + + +// notifyInitAddOtherDevice() - notify InitAddOtherDevice to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitAddOtherDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE); +} + + +// notifyInitMoveOurDevice() - notify InitMoveOurDevice to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitMoveOurDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE); +} + + +// notifyOvertaken() - notify Overtaken to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyOvertaken( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_OVERTAKEN); +} + + +// notifyAcceptedDeviceMoved() - notify AcceptedDeviceMoved to app +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedDeviceMoved( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + assert(session && state); + assert(extra == NULL); + if (!(session && state && extra == NULL)) + return PEP_ILLEGAL_VALUE; + + return _notifyHandshake(session, partner, SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED); +} + diff --git a/sync/skeletons/sync_actions.c b/sync/skeletons/sync_actions.c new file mode 100644 index 00000000..169caeeb --- /dev/null +++ b/sync/skeletons/sync_actions.c @@ -0,0 +1,564 @@ +// Actions for DeviceState state machine + +#include +#include "pEp_internal.h" +#include "keymanagement.h" +#include "message.h" +#include "sync_fsm.h" +#include "../asn.1/DeviceGroup-Protocol.h" + + +// notifyInitFormGroup() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitFormGroup( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyInitAddOurDevice() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitAddOurDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// rejectHandshake() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS rejectHandshake( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// acceptHandshake() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS acceptHandshake( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// makeGroup() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) (must be NULL) +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS makeGroup( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// renewUUID() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) (must be NULL) +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS renewUUID( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyAcceptedGroupCreated() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedGroupCreated( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyTimeout() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyTimeout( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(!partner); + if (!(session && !partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// storeGroupKeys() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS storeGroupKeys( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyAcceptedDeviceAdded() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedDeviceAdded( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// storeGroupUpdate() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS storeGroupUpdate( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyInitAddOtherDevice() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitAddOtherDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyInitMoveOurDevice() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyInitMoveOurDevice( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyOvertaken() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyOvertaken( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} + + +// notifyAcceptedDeviceMoved() - +// +// params: +// session (in) session handle +// state (in) state the state machine is in +// partner (in) partner to communicate with +// +// returns: +// PEP_STATUS_OK or any other value on error + +PEP_STATUS notifyAcceptedDeviceMoved( + PEP_SESSION session, + DeviceState_state state, + Identity partner, + void *extra + ) +{ + PEP_STATUS status = PEP_STATUS_OK; + + assert(session); + assert(partner); + if (!(session && partner)) + return PEP_ILLEGAL_VALUE; + + // working code + + // free extra + return status; + +enomem: + status = PEP_OUT_OF_MEMORY; +error: + // free extra + return status; +} +