Browse Source

Removed all 2-party keysync components from engine.

doc_update_sequoia
Krista Bennett 5 years ago
parent
commit
6b51966b22
24 changed files with 1 additions and 6307 deletions
  1. +0
    -2
      Makefile
  2. +1
    -1
      src/Makefile
  3. +0
    -13
      src/keymanagement.c
  4. +0
    -3
      src/pEpEngine.c
  5. +0
    -6
      src/pEp_internal.h
  6. +0
    -288
      src/sync.c
  7. +0
    -417
      src/sync.h
  8. +0
    -434
      src/sync_actions.c
  9. +0
    -34
      src/sync_app.h
  10. +0
    -971
      src/sync_impl.c
  11. +0
    -64
      src/sync_impl.h
  12. +0
    -38
      sync/Makefile
  13. +0
    -354
      sync/devicegroup.fsm
  14. +0
    -19
      sync/fsm.yml2
  15. +0
    -15
      sync/functions.ysl2
  16. +0
    -300
      sync/gen_actions.ysl2
  17. +0
    -42
      sync/gen_dot.ysl2
  18. +0
    -415
      sync/gen_statemachine.ysl2
  19. +0
    -11
      sync/generated/README
  20. +0
    -40
      sync/generated/sync_driver.c
  21. +0
    -1610
      sync/generated/sync_fsm.c
  22. +0
    -145
      sync/generated/sync_fsm.h
  23. +0
    -521
      sync/generated/sync_send_actions.c
  24. +0
    -564
      sync/skeletons/sync_actions.c

+ 0
- 2
Makefile View File

@ -23,7 +23,6 @@ endif
all:
$(MAKE) -C asn.1 generate
$(MAKE) -C asn.1
$(MAKE) -C sync
$(MAKE) -C src all
.PHONY: install
@ -41,7 +40,6 @@ 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


+ 1
- 1
src/Makefile View File

@ -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 sync.h sync_fsm.h sync_app.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 blacklist.h openpgp_compat.h $(PREFIX)/include/pEp/
.PHONY: uninstall
uninstall:


+ 0
- 13
src/keymanagement.c View File

@ -12,7 +12,6 @@
#include "pEp_internal.h"
#include "keymanagement.h"
#include "sync_fsm.h"
#include "blacklist.h"
#ifndef EMPTYSTR
@ -555,8 +554,6 @@ PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen,
}
}
bool new_key_generated = false;
if (EMPTYSTR(identity->fpr) || revoked)
{
if(!do_keygen){
@ -581,7 +578,6 @@ PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen,
return ADD_TO_LOG(status);
}
new_key_generated = true;
if(revoked)
{
@ -621,15 +617,6 @@ PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen,
return status;
}
if(new_key_generated)
{
// if a state machine for keysync is in place, inject notify
status = inject_DeviceState_event(session, KeyGen, NULL, NULL);
if (status == PEP_OUT_OF_MEMORY){
return PEP_OUT_OF_MEMORY;
}
}
return ADD_TO_LOG(PEP_STATUS_OK);
}


+ 0
- 3
src/pEpEngine.c View File

@ -6,7 +6,6 @@
#include "cryptotech.h"
#include "transport.h"
#include "blacklist.h"
#include "sync_fsm.h"
#include <time.h>
#include <stdlib.h>
@ -826,8 +825,6 @@ DYNAMIC_API void release(PEP_SESSION session)
out_last = true;
if (session) {
if (session->sync_state != DeviceState_state_NONE)
unregister_sync_callbacks(session);
if (session->db) {
if (session->log)


+ 0
- 6
src/pEp_internal.h View File

@ -101,7 +101,6 @@
#include "keymanagement.h"
#include "cryptotech.h"
#include "transport.h"
#include "sync.h"
#define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR;
@ -168,14 +167,9 @@ 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;


+ 0
- 288
src/sync.c View File

@ -1,288 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include "pEp_internal.h"
#include <memory.h>
#include <assert.h>
#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;
}

+ 0
- 417
src/sync.h View File

@ -1,417 +0,0 @@
// 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

+ 0
- 434
src/sync_actions.c View File

@ -1,434 +0,0 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
// Actions for DeviceState state machine
#include <assert.h>
#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;
}

+ 0
- 34
src/sync_app.h View File

@ -1,34 +0,0 @@
//
// 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 */

+ 0
- 971
src/sync_impl.c View File

@ -1,971 +0,0 @@
// 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.