@ -1,60 +0,0 @@ | |||
/* This file is under GNU General Public License 3.0 */ | |||
/* see LICENSE.txt */ | |||
DEVICEGROUP | |||
{ iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) pEp (47878) sync(1) keysync(1) } | |||
DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::= | |||
BEGIN | |||
EXPORTS DeviceGroup-Protocol; | |||
IMPORTS Version, Identity, IdentityList FROM PEP; | |||
Beacon ::= NULL | |||
HandshakeRequest ::= SEQUENCE { | |||
/* UUID of receiver, group UUID if grouped */ | |||
partner-id UTF8String (SIZE(1..1024)) OPTIONAL, | |||
/* Group UUID of sender, if grouped */ | |||
group-id UTF8String (SIZE(1..1024)) OPTIONAL | |||
} | |||
GroupKeys ::= SEQUENCE { | |||
/* UUID of receiver */ | |||
partner-id UTF8String (SIZE(1..1024)) OPTIONAL, | |||
/* Group UUID of sender */ | |||
group-id UTF8String (SIZE(1..1024)) OPTIONAL, | |||
ownIdentities IdentityList | |||
} | |||
GroupUpdate ::= SEQUENCE { | |||
ownIdentities IdentityList | |||
} | |||
/* TODO: narrow request to single key */ | |||
UpdateRequest ::= NULL | |||
/* for the tags see end of sync.fsm */ | |||
DeviceGroup-Protocol ::= SEQUENCE { | |||
header SEQUENCE { | |||
version Version, | |||
sequence INTEGER, /* always increases */ | |||
me Identity, /* identity of the sender */ | |||
state INTEGER, /* state the sender is in */ | |||
devicegroup BOOLEAN | |||
/* signals if this message is coming from a device group member */ | |||
}, | |||
payload CHOICE { | |||
beacon [APPLICATION 2] Beacon, | |||
handshakeRequest [APPLICATION 3] HandshakeRequest, | |||
groupKeys [APPLICATION 4] GroupKeys, | |||
groupUpdate [APPLICATION 5] GroupUpdate, | |||
updateRequest [APPLICATION 6] UpdateRequest | |||
} | |||
} | |||
END | |||
@ -1,17 +0,0 @@ | |||
/* This file is under GNU General Public License 3.0 */ | |||
/* see LICENSE.txt */ | |||
SYNC | |||
DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::= | |||
BEGIN | |||
IMPORTS DeviceGroup-Protocol FROM DEVICEGROUP; | |||
Sync-Protocols ::= CHOICE { | |||
deviceGroup [APPLICATION 1] DeviceGroup-Protocol | |||
} | |||
END | |||
@ -0,0 +1,43 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
// generate state machine code | |||
// Copyleft (c) 2017, p≡p foundation | |||
// Written by Volker Birk | |||
#pragma once | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
// 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; | |||
// common | |||
enum { | |||
End = -1, | |||
None = 0, | |||
Init = 1, | |||
Extra = 128 // messages will be below this ID | |||
}; | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
@ -0,0 +1,285 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
// generate conditions and actions | |||
// Copyleft (c) 2017, p≡p foundation | |||
// Written by Volker Birk | |||
// prepare SQL statement | |||
function "init_sql" { | |||
param "sql"; | |||
|| | |||
static const char *sql = `copy '$sql'`; | |||
static const size_t len = sizeof(`copy '$sql'`); | |||
sqlite3_stmt *_sql; | |||
int int_result = sqlite3_prepare_v2(session->db, sql, (int) len, &_sql, NULL); | |||
assert(int_result == SQLITE_OK); | |||
if (!(int_result == SQLITE_OK)) | |||
return PEP_UNKNOWN_ERROR; | |||
|| | |||
} | |||
// exec_sql_* is returning _result | |||
function "exec_sql_int" { | |||
param "sql"; | |||
call "init_sql" with "sql", "$sql"; | |||
|| | |||
int _result = 0; | |||
int_result = sqlite3_step(_sql); | |||
assert(int_result == SQLITE_ROW); | |||
if (int_result == SQLITE_ROW) | |||
_result = sqlite3_column_int(_sql, 0); | |||
sqlite3_finalize(_sql); | |||
if (int_result != SQLITE_ROW) | |||
return PEP_UNKNOWN_ERROR; | |||
|| | |||
} | |||
// condition: PEP_STATUS «@name»(PEP_SESSION session, bool *result) | |||
condition deviceGrouped { | |||
call "exec_sql_int" with "sql" | |||
> "select count(*) from identity where user_id = '"PEP_OWN_USERID"' and (flags & 4) = 4;" | |||
|> *result = _result > 0; | |||
} | |||
condition partnerIsGrouped | |||
|> *result = session->sync_state.keysync.is_group; | |||
condition challengeAccepted | |||
|| | |||
TID_t *t1 = &session->sync_state.keysync.challenge; | |||
TID_t *t2 = &session->own_sync_state.challenge; | |||
*result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0; | |||
|| | |||
condition keyElectionWon | |||
|| | |||
pEp_identity *from = session->sync_state.basic.from; | |||
assert(from && from->fpr && from->fpr[0] && from->address && from->address[0]); | |||
if (!(from && from->fpr && from->fpr[0] && from->address && from->address[0])) | |||
return PEP_ILLEGAL_VALUE; | |||
pEp_identity *me = NULL; | |||
PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me); | |||
assert(status == PEP_STATUS_OK); | |||
if (status) | |||
return status; | |||
assert(me->fpr && me->fpr[0]); | |||
if (!(me->fpr && me->fpr[0])) { | |||
free_identity(me); | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
size_t len = MIN(strlen(from->fpr), strlen(me->fpr)); | |||
*result = strncasecmp(from->fpr, me->fpr, len) > 0; | |||
free_identity(me); | |||
|| | |||
// action: PEP_STATUS «@name»(PEP_SESSION session) | |||
action closeHandshakeDialog | |||
|| | |||
assert(session->notifyHandshake); | |||
if (!session->notifyHandshake) | |||
return PEP_SYNC_NO_NOTIFY_CALLBACK; | |||
PEP_STATUS status = session->notifyHandshake( | |||
session->sync_management, NULL, NULL, SYNC_NOTIFY_OVERTAKEN); | |||
if (status) | |||
return status; | |||
|| | |||
function "new_UUID" { | |||
param "dst"; | |||
|| | |||
pEpUUID c; | |||
uuid_generate_random(c); | |||
OCTET_STRING_fromBuf(«$dst», (char *) c, 16); | |||
|| | |||
} | |||
function "copy_UUID" { | |||
param "src", param "dst"; | |||
|| | |||
TID_t *src = «$src»; | |||
TID_t *dst = «$dst»; | |||
assert(src->size == 16); | |||
if (!(src->size == 16)) | |||
return PEP_UNKNOWN_ERROR; | |||
OCTET_STRING_fromBuf(dst, (char *) src->buf, src->size); | |||
|| | |||
} | |||
action openChallenge | |||
call "new_UUID" with "dst" > &session->own_sync_state.challenge | |||
action storeChallenge call "copy_UUID" { | |||
with "src" > &session->sync_state.keysync.challenge | |||
with "dst" > &session->own_sync_state.challenge | |||
} | |||
action openTransaction | |||
call "new_UUID" with "dst" > &session->own_sync_state.transaction | |||
action storeTransaction call "copy_UUID" { | |||
with "src" > &session->sync_state.keysync.transaction | |||
with "dst" > &session->own_sync_state.transaction | |||
} | |||
function "show_handshake" { | |||
param "type"; | |||
|| | |||
assert(session->notifyHandshake); | |||
if (!session->notifyHandshake) | |||
return PEP_SYNC_NO_NOTIFY_CALLBACK; | |||
assert(session->sync_state.basic.from); | |||
if (!session->sync_state.basic.from) | |||
return PEP_ILLEGAL_VALUE; | |||
pEp_identity *from = session->sync_state.basic.from; | |||
pEp_identity *me = NULL; | |||
PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me); | |||
assert(status == PEP_STATUS_OK); | |||
if (status) | |||
return status; | |||
assert(me->fpr && me->fpr[0]); | |||
if (!(me->fpr && me->fpr[0])) { | |||
free_identity(me); | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
pEp_identity *partner = identity_dup(from); | |||
if (!partner) { | |||
free_identity(me); | |||
return PEP_OUT_OF_MEMORY; | |||
} | |||
status = session->notifyHandshake(session->sync_management, me, | |||
partner, «$type»); | |||
if (status) | |||
return status; | |||
|| | |||
} | |||
action showSoleHandshake | |||
call "show_handshake" with "type" > SYNC_NOTIFY_INIT_FORM_GROUP | |||
action showJoinGroupHandshake | |||
call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OUR_DEVICE | |||
action showGroupedHandshake | |||
call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE | |||
action saveGroupKeys | |||
|| | |||
identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.identities, NULL); | |||
if (!il) | |||
return PEP_OUT_OF_MEMORY; | |||
// BUG: this should be a transaction and been rolled back completely on error | |||
for (identity_list *_il = il; _il && _il->ident; _il = _il->next) { | |||
PEP_STATUS status = set_identity(session, _il->ident); | |||
if (status) { | |||
free_identity_list(il); | |||
return status; | |||
} | |||
} | |||
free_identity_list(il); | |||
|| | |||
action ownKeysAreGroupKeys { | |||
call "init_sql" with "sql" { | |||
|| | |||
"select fpr, username, comm_type, lang," | |||
" identity.flags | pgp_keypair.flags" | |||
" from identity" | |||
" join person on id = identity.user_id" | |||
" join pgp_keypair on fpr = identity.main_key_id" | |||
" join trust on id = trust.user_id" | |||
" and pgp_keypair_fpr = identity.main_key_id" | |||
|| | |||
> " where identity.user_id = '" PEP_OWN_USERID "';" | |||
} | |||
|| | |||
identity_list *il = new_identity_list(NULL); | |||
if (!il) | |||
return PEP_OUT_OF_MEMORY; | |||
pEp_identity *from = session->sync_state.basic.from; | |||
identity_list *_il = il; | |||
int result; | |||
do { | |||
result = sqlite3_step(_sql); | |||
pEp_identity *_identity = NULL; | |||
switch (result) { | |||
case SQLITE_ROW: | |||
_identity = new_identity( | |||
from->address, | |||
(const char *) sqlite3_column_text(_sql, 0), | |||
from->user_id, | |||
(const char *) sqlite3_column_text(_sql, 1) | |||
); | |||
assert(_identity); | |||
if (_identity == NULL) | |||
return PEP_OUT_OF_MEMORY; | |||
_identity->comm_type = (PEP_comm_type) | |||
sqlite3_column_int(_sql, 2); | |||
const char* const _lang = (const char *) | |||
sqlite3_column_text(_sql, 3); | |||
if (_lang && _lang[0]) { | |||
assert(_lang[0] >= 'a' && _lang[0] <= 'z'); | |||
assert(_lang[1] >= 'a' && _lang[1] <= 'z'); | |||
assert(_lang[2] == 0); | |||
_identity->lang[0] = _lang[0]; | |||
_identity->lang[1] = _lang[1]; | |||
_identity->lang[2] = 0; | |||
} | |||
_identity->flags = (unsigned int) | |||
sqlite3_column_int(_sql, 4); | |||
_il = identity_list_add(_il, _identity); | |||
if (!_il) { | |||
free_identity_list(il); | |||
free_identity(_identity); | |||
return PEP_OUT_OF_MEMORY; | |||
} | |||
break; | |||
case SQLITE_DONE: | |||
break; | |||
default: | |||
free_identity_list(il); | |||
return PEP_UNKNOWN_ERROR; | |||
} | |||
} while (result != SQLITE_DONE); | |||
IdentityList_t *r = IdentityList_from_identity_list(il, &session->sync_state.keysync.identities); | |||
free_identity_list(il); | |||
if (!r) | |||
return PEP_OUT_OF_MEMORY; | |||
|| | |||
} | |||
action disable; | |||
@ -1,354 +0,0 @@ | |||
// 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; | |||
} | |||
} | |||
@ -0,0 +1,319 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
// generate message functions | |||
// Copyleft (c) 2017, p≡p foundation | |||
// Written by Volker Birk | |||
include yslt.yml2 | |||
tstylesheet { | |||
include standardlib.ysl2 | |||
include ./functions.ysl2 | |||
template "/" { | |||
apply "protocol", 0, mode=header; | |||
apply "protocol", 0, mode=impl; | |||
} | |||
template "protocol", mode=header | |||
document "generated/{@name}_func.h", "text" | |||
|| | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
#pragma once | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#include <stdbool.h> | |||
#include "../asn.1/«@name».h" | |||
`` for "func:distinctType(fsm/message/field[not(func:basicType())])" | #include "../asn.1/«@type».h" | |||
// state | |||
struct «@name»_state_s { | |||
struct basic_state_s { | |||
pEp_identity *from; | |||
} basic; | |||
`` apply "fsm", mode=state | |||
}; | |||
struct own_«@name»_state_s { | |||
`` for "func:distinctName(fsm/message/field[@type='TID'])" |> «func:ctype()» «@name»; | |||
}; | |||
void free_«@name»_state(PEP_SESSION session); | |||
// functions for protocol «@name» | |||
«@name»_t *new_«@name»_message(«@name»_PR fsm, int message_type); | |||
void free_«@name»_message(«@name»_t *msg); | |||
PEP_STATUS update_«@name»_state(PEP_SESSION session, «@name»_t *msg, | |||
«@name»_PR *fsm, int *message_type); | |||
PEP_STATUS update_«@name»_message(PEP_SESSION session, «@name»_PR fsm, | |||
int message_type, «@name»_t *msg); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
|| | |||
template "fsm", mode=state | |||
|| | |||
struct _«@name»_state_s { | |||
int state; | |||
`` for "func:distinctName(message/field)" |> «func:ctype()» «@name»; | |||
} «yml:lcase(@name)»; | |||
|| | |||
template "protocol", mode=impl | |||
document "generated/{@name}_func.c", "text" { | |||
|| | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
#include <assert.h> | |||
#include <stdlib.h> | |||
#include "pEp_internal.h" | |||
#include "map_asn1.h" | |||
#include "«@name»_func.h" | |||
void free_«@name»_state(PEP_SESSION session) | |||
{ | |||
if (!session) | |||
return; | |||
free_identity(session->«yml:lcase(@name)»_state.basic.from); | |||
session->«yml:lcase(@name)»_state.basic.from = NULL; | |||
|| | |||
for "fsm" | |||
for "func:distinctName(message/field[not(func:basicType())])" | |||
|> ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_«@type», &session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»); | |||
| | |||
for "func:distinctName(fsm/message/field[@type='TID'])" | |||
|> ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_«@type», &session->own_«yml:lcase(../../../@name)»_state.«@name»); | |||
|| | |||
} | |||
«@name»_t *new_«@name»_message(«@name»_PR fsm, int message_type) | |||
{ | |||
assert(fsm && message_type); | |||
if (!(fsm && message_type)) | |||
return NULL; | |||
«@name»_t *msg = calloc(sizeof(«@name»_t), 1); | |||
assert(msg); | |||
if (!msg) | |||
return NULL; | |||
msg->present = fsm; | |||
switch (fsm) { | |||
`` apply "fsm", mode=impl | |||
default: | |||
free(msg); | |||
return NULL; | |||
} | |||
return msg; | |||
} | |||
void free_«@name»_message(«@name»_t *msg) | |||
{ | |||
ASN_STRUCT_FREE(asn_DEF_«@name», msg); | |||
} | |||
PEP_STATUS update_«@name»_state(PEP_SESSION session, «@name»_t *msg, | |||
«@name»_PR *fsm, int *message_type) | |||
{ | |||
int result = 0; | |||
assert(session && msg && fsm && message_type); | |||
if (!(session && msg && fsm && message_type)) | |||
return PEP_ILLEGAL_VALUE; | |||
*fsm = 0; | |||
*message_type = 0; | |||
switch (msg->present) { | |||
case «@name»_PR_NOTHING: | |||
return PEP_ILLEGAL_VALUE; | |||
`` apply "fsm", 2, mode=update_state | |||
default: | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
*fsm = msg->present; | |||
return PEP_STATUS_OK; | |||
} | |||
PEP_STATUS update_«@name»_message(PEP_SESSION session, «@name»_PR fsm, | |||
int message_type, «@name»_t *msg) | |||
{ | |||
int result = 0; | |||
assert(session && msg); | |||
if (!(session && msg)) | |||
return PEP_ILLEGAL_VALUE; | |||
switch (fsm) { | |||
case «@name»_PR_NOTHING: | |||
return PEP_ILLEGAL_VALUE; | |||
`` apply "fsm", 2, mode=update_message | |||
default: | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
return PEP_STATUS_OK; | |||
} | |||
|| | |||
} | |||
template "fsm", mode=update_message | |||
|| | |||
case «../@name»_PR_«yml:lcase(@name)»: | |||
switch (message_type) { | |||
case «@name»__payload_PR_NOTHING: | |||
return PEP_ILLEGAL_VALUE; | |||
`` apply "message", 2, mode=update_message | |||
default: | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
break; | |||
|| | |||
template "message", mode=update_message { | |||
const "message_name", "concat(yml:lcase(substring(@name,1,1)), substring(@name,2))"; | |||
|| | |||
case «../@name»__payload_PR_«$message_name»: | |||
`` apply "field", mode=update_message with "message_name", "$message_name" | |||
break; | |||
|| | |||
} | |||
template "field", mode=update_message { | |||
param "message_name"; | |||
choose { | |||
when "func:basicType()" // copyable | |||
|| | |||
msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name» | |||
= session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»; | |||
|| | |||
when "@type='IdentityList'" | |||
|| | |||
{ | |||
identity_list *il = IdentityList_to_identity_list( | |||
&session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name», NULL); | |||
if (!il) | |||
return PEP_OUT_OF_MEMORY; | |||
IdentityList_t *_il = IdentityList_from_identity_list(il, | |||
&msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name»); | |||
free_identity_list(il); | |||
if (!_il) | |||
return PEP_OUT_OF_MEMORY; | |||
} | |||
|| | |||
otherwise // string based | |||
|| | |||
result = OCTET_STRING_fromBuf(&msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name», | |||
(char *) session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name».buf, | |||
session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name».size); | |||
if (result) | |||
return PEP_OUT_OF_MEMORY; | |||
|| | |||
} | |||
} | |||
template "fsm", mode=update_state | |||
|| | |||
case «../@name»_PR_«yml:lcase(@name)»: | |||
switch (msg->choice.«yml:lcase(@name)».payload.present) { | |||
case «@name»__payload_PR_NOTHING: | |||
return PEP_ILLEGAL_VALUE; | |||
`` apply "message", 2, mode=update_state | |||
default: | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
*message_type = msg->choice.«yml:lcase(@name)».payload.present; | |||
break; | |||
|| | |||
template "message", mode=update_state { | |||
const "message_name", "concat(yml:lcase(substring(@name,1,1)), substring(@name,2))"; | |||
|| | |||
case «../@name»__payload_PR_«$message_name»: | |||
`` apply "field", mode=update_state with "message_name", "$message_name" | |||
break; | |||
|| | |||
} | |||
template "field", mode=update_state { | |||
param "message_name"; | |||
choose { | |||
when "func:basicType()" // copyable | |||
|| | |||
session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name» = msg->choice.«yml:lcase(../../@name)» | |||
.payload.choice.«$message_name».«@name»; | |||
|| | |||
when "@type='IdentityList'" | |||
|| | |||
{ | |||
identity_list *il = IdentityList_to_identity_list( | |||
&msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name», NULL); | |||
if (!il) | |||
return PEP_OUT_OF_MEMORY; | |||
IdentityList_t *_il = IdentityList_from_identity_list(il, | |||
&session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name»); | |||
free_identity_list(il); | |||
if (!_il) | |||
return PEP_OUT_OF_MEMORY; | |||
} | |||
|| | |||
otherwise // string based | |||
|| | |||
result = OCTET_STRING_fromBuf(&session->«yml:lcase(../../../@name)»_state.«yml:lcase(../../@name)».«@name», | |||
(char *) msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name».buf, | |||
msg->choice.«yml:lcase(../../@name)».payload.choice.«$message_name».«@name».size); | |||
if (result) | |||
return PEP_OUT_OF_MEMORY; | |||
|| | |||
} | |||
} | |||
template "fsm", mode=impl | |||
|| | |||
case «../@name»_PR_«yml:lcase(@name)»: | |||
msg->choice.«yml:lcase(@name)».payload.present = message_type; | |||
break; | |||
|| | |||
} | |||
@ -0,0 +1,100 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
// generated files of this template are under BSD License 2.0 | |||
// generate message functions | |||
// Copyleft (c) 2017, p≡p foundation | |||
// Written by Volker Birk | |||
include yslt.yml2 | |||
tstylesheet { | |||
include standardlib.ysl2 | |||
include ./functions.ysl2 | |||
function "pEp_imports" | |||
| IMPORTS Identity, IdentityList, TID, Hash FROM PEP; | |||
template "/" { | |||
apply "protocol", 0, mode=overview; | |||
apply "protocol/fsm", 0, mode=individual; | |||
} | |||
template "protocol", mode=overview | |||
document "generated/{yml:lcase(@name)}.asn1", "text" | |||
|| | |||
-- This file is under BSD License 2.0 | |||
-- «@name» protocol stack for p≡p | |||
-- Copyright (c) 2016, 2017 p≡p foundation | |||
-- Written by Volker Birk | |||
«yml:ucase(@name)» | |||
{ iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) pEp(47878) «yml:lcase(@name)»(«@id») } | |||
DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::= | |||
BEGIN | |||
`` for "fsm" | IMPORTS «@name» FROM «yml:ucase(@name)»; | |||
«@name» ::= CHOICE { | |||
`` for "fsm" |> «yml:lcase(@name)» [APPLICATION «@id»] «@name»`if "position()!=last()" > , ` | |||
} | |||
END | |||
|| | |||
template "fsm", mode=individual | |||
document "generated/{yml:lcase(@name)}.asn1", "text" | |||
|| | |||
-- This file is under BSD License 2.0 | |||
-- «@name» protocol for p≡p version «version/@major».«version/@minor» | |||
-- Copyright (c) 2016, 2017 p≡p foundation | |||
-- Written by Volker Birk | |||
«yml:ucase(@name)» | |||
{ iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) pEp(47878) «yml:lcase(../@name)»(«../@id») «yml:lcase(@name)»(«@id») } | |||
DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::= | |||
BEGIN | |||
EXPORTS «@name»; | |||
`` call "pEp_imports" | |||
Version ::= SEQUENCE { | |||
major INTEGER (0..255) DEFAULT «version/@major», | |||
minor INTEGER (0..255) DEFAULT «version/@minor» | |||
} | |||
`` apply "message", 0, mode=impl; | |||
«@name» ::= SEQUENCE { | |||
header SEQUENCE { | |||
sequence INTEGER -- always increases | |||
}, | |||
payload CHOICE { | |||
`` for "message" |>> «yml:mixedCase(@name)» [APPLICATION «@id»] «@name»`if "position()!=last()" > ,` | |||
} | |||
} | |||
END | |||
|| | |||
template "message", mode=impl | |||
|| | |||
«@name» ::= SEQUENCE { | |||
`` for "field|auto" |> «func:asn1name()» «func:asn1type()»`if "position()!=last()" > ,` | |||
} | |||
|| | |||
} | |||
@ -1,40 +0,0 @@ | |||
// Driver for DeviceState state machine | |||
#include <assert.h> | |||
#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; | |||
} | |||
@ -1,145 +0,0 @@ | |||
#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 | |||
@ -1,521 +0,0 @@ | |||
// Send Actions for DeviceState state machine | |||
#include <assert.h> | |||
#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 | |||