put sync.fsm excerpt to external file, update it from sources, cut and add lines breaks avoid too long lines

pull/117/head
Bernie Hoeneisen 2 months ago
parent ae053a06a1
commit 5f55f76692

@ -37,6 +37,7 @@ $(DRAFT).xml: $(NAME).mkd \
../shared/ascii-arts/sync/join-device-group_cancel.atxt \
../shared/ascii-arts/sync/join-device-group.atxt \
../shared/text-blocks/more-info-following-code.mkd \
excerpts/sync.fsm \
# ../shared/author_tags/claudio_luck.mkd \
# ../shared/author_tags/hernani_marques.mkd \
# ../shared/ascii-arts/basic-msg-flow.mkd \

@ -1827,688 +1827,11 @@ For more information on the messages used in the KeySync Protocol, see (end of)
## Finite State Machine {#finite-state-machine-code}
Below is the full code for the pEp KeySync FSM, including messages and external events.
Below you can find the code excerpt for the pEp KeySync FSM, including messages and external events:
{::include ../shared/fence-line.mkd}
// This file is under BSD License 2.0
// Sync protocol for pEp
// Copyright (c) 2016-2020, pEp foundation
// Written by Volker Birk
include ./fsm.yml2
protocol Sync 1 {
// all messages have a timestamp, time out and are removed after
// timeout
fsm KeySync 1, threshold=300 {
version 1, 2;
state InitState {
on Init {
if deviceGrouped {
send SynchronizeGroupKeys;
go Grouped;
}
go Sole;
}
}
state Sole timeout=off {
on Init {
do newChallengeAndNegotiationBase;
send Beacon;
do showBeingSole;
}
on KeyGen {
send Beacon;
}
on CannotDecrypt {
send Beacon;
}
on Beacon {
if sameChallenge {
}
else {
if weAreOfferer {
do useOwnChallenge;
send Beacon;
}
else /* we are requester */ {
do openNegotiation;
do tellWeAreNotGrouped;
// requester is sending NegotiationRequest
do useOwnResponse;
send NegotiationRequest;
do useOwnChallenge;
}
}
}
// we get this from another sole device
on NegotiationRequest {
if sameChallenge { // challenge accepted
do storeNegotiation;
// offerer is accepting by confirming
// NegotiationOpen
// repeating response is implicit
send NegotiationOpen;
go HandshakingOfferer;
}
}
// we get this from an existing device group
on NegotiationRequestGrouped {
if sameChallenge { // challenge accepted
do storeNegotiation;
// offerer is accepting by confirming
// NegotiationOpen
// repeating response is implicit
send NegotiationOpen;
go HandshakingToJoin;
}
}
on NegotiationOpen {
if sameResponse {
do storeNegotiation;
go HandshakingRequester;
}
}
}
// handshaking without existing Device group
state HandshakingOfferer timeout=600 {
on Init
do showSoleHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept means init Phase1Commit
on Accept {
do trustThisKey;
go HandshakingPhase1Offerer;
}
// got a CommitAccept from requester
on CommitAcceptRequester {
if sameNegotiation
go HandshakingPhase2Offerer;
}
}
// handshaking without existing Device group
state HandshakingRequester timeout=600 {
on Init
do showSoleHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept means init Phase1Commit
on Accept {
do trustThisKey;
send CommitAcceptRequester;
go HandshakingPhase1Requester;
}
}
state HandshakingPhase1Offerer {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptRequester {
if sameNegotiation {
send CommitAcceptOfferer;
go FormingGroupOfferer;
}
}
}
state HandshakingPhase1Requester {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptOfferer {
if sameNegotiation {
do prepareOwnKeys;
send OwnKeysRequester;
go FormingGroupRequester;
}
}
}
state HandshakingPhase2Offerer {
on Cancel {
send Rollback;
go Sole;
}
on Reject {
send CommitReject;
do disable;
go End;
}
on Accept {
do trustThisKey;
send CommitAcceptOfferer;
go FormingGroupOfferer;
}
}
state FormingGroupOfferer {
on Init {
// we need to keep in memory which keys we have before
// forming a new group
do prepareOwnKeys;
do backupOwnKeys;
}
on Cancel {
send Rollback;
go Sole;
}
on Rollback
go Sole;
on OwnKeysRequester {
if sameNegotiationAndPartner {
do saveGroupKeys;
do receivedKeysAreDefaultKeys;
// send the keys we had before forming a new group
do prepareOwnKeysFromBackup;
send OwnKeysOfferer;
do showGroupCreated;
go Grouped;
}
}
}
state FormingGroupRequester {
on Cancel {
send Rollback;
go Sole;
}
on Rollback
go Sole;
on OwnKeysOfferer {
if sameNegotiation {
do saveGroupKeys;
do prepareOwnKeys;
do ownKeysAreDefaultKeys;
do showGroupCreated;
go Grouped;
}
}
}
state Grouped timeout=off {
on Init {
do newChallengeAndNegotiationBase;
do showBeingInGroup;
}
on CannotDecrypt {
send SynchronizeGroupKeys;
}
on SynchronizeGroupKeys {
do prepareOwnKeys;
send GroupKeysUpdate;
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
on KeyGen {
do prepareOwnKeys;
send GroupKeysUpdate;
}
on Beacon {
do openNegotiation;
do tellWeAreGrouped;
do useOwnResponse;
send NegotiationRequestGrouped;
do useOwnChallenge;
}
on NegotiationOpen {
if sameResponse {
do storeNegotiation;
do useThisKey;
send GroupHandshake;
go HandshakingGrouped;
}
}
on GroupHandshake {
do storeNegotiation;
do storeThisKey;
go HandshakingGrouped;
}
on GroupTrustThisKey {
if fromGroupMember // double check
do trustThisKey;
}
on LeaveDeviceGroup {
send InitUnledGroupKeyReset;
do disable;
do resetOwnKeysUngrouped;
}
on InitUnledGroupKeyReset {
do useOwnResponse;
send ElectGroupKeyResetLeader;
go GroupKeyResetElection;
}
}
state GroupKeyResetElection {
on ElectGroupKeyResetLeader {
if sameResponse {
// the first one is from us, we're leading this
do resetOwnGroupedKeys;
go Grouped;
}
else {
// the first one is not from us
go Grouped;
}
}
}
// sole device handshaking with group
state HandshakingToJoin {
on Init
do showJoinGroupHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitAcceptForGroup {
if sameNegotiation
go HandshakingToJoinPhase2;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept is Phase1Commit
on Accept {
do trustThisKey;
go HandshakingToJoinPhase1;
}
}
state HandshakingToJoinPhase1 {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptForGroup {
if sameNegotiation {
send CommitAccept;
go JoiningGroup;
}
}
}
state HandshakingToJoinPhase2 {
on Cancel {
send Rollback;
go Sole;
}
on Reject {
send CommitReject;
do disable;
go End;
}
on Accept {
do trustThisKey;
send CommitAccept;
go JoiningGroup;
}
}
state JoiningGroup {
on Init {
// we need to keep in memory which keys we have before
// joining
do prepareOwnKeys;
do backupOwnKeys;
}
on GroupKeysForNewMember {
if sameNegotiationAndPartner {
do saveGroupKeys;
do receivedKeysAreDefaultKeys;
// send the keys we had before joining
do prepareOwnKeysFromBackup;
send GroupKeysAndClose;
do showDeviceAdded;
go Grouped;
}
}
}
state HandshakingGrouped {
on Init
do showGroupedHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Grouped;
}
on Rollback {
if sameNegotiation
go Grouped;
}
// Reject is CommitReject
on Reject {
send CommitReject;
go Grouped;
}
on CommitReject {
if sameNegotiation
go Grouped;
}
// Accept is Phase1Commit
on Accept {
do trustThisKey;
go HandshakingGroupedPhase1;
}
on GroupTrustThisKey {
if fromGroupMember { // double check
do trustThisKey;
if sameNegotiation
go Grouped;
}
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
}
state HandshakingGroupedPhase1 {
on Init {
send GroupTrustThisKey;
send CommitAcceptForGroup;
}
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Grouped;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
go Grouped;
}
}
on CommitAccept {
if sameNegotiation {
do prepareOwnKeys;
send GroupKeysForNewMember;
do showDeviceAccepted;
go Grouped;
}
}
on GroupTrustThisKey {
if fromGroupMember // double check
do trustThisKey;
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
on GroupKeysAndClose {
if fromGroupMember { // double check
// do not save GroupKeys as default keys;
// key data is already imported
go Grouped;
}
}
}
external Accept 129;
external Reject 130;
external Cancel 131;
// beacons are always broadcasted
message Beacon 2, type=broadcast, ratelimit=10,
security=unencrypted {
field TID challenge;
auto Version version;
}
message NegotiationRequest 3, security=untrusted {
field TID challenge;
field TID response;
auto Version version;
field TID negotiation;
field bool is_group;
}
message NegotiationOpen 4, security=untrusted {
field TID response;
auto Version version;
field TID negotiation;
}
message Rollback 5, security=untrusted {
field TID negotiation;
}
message CommitReject 6, security=untrusted {
field TID negotiation;
}
message CommitAcceptOfferer 7, security=untrusted {
field TID negotiation;
}
message CommitAcceptRequester 8, security=untrusted {
field TID negotiation;
}
message CommitAccept 9, security=untrusted {
field TID negotiation;
}
message CommitAcceptForGroup 10, security=untrusted {
field TID negotiation;
}
// default: security=trusted
// messages are only accepted when coming from the device group
message GroupTrustThisKey 11 {
field Hash key;
field TID negotiation;
}
// trust in future
message GroupKeysForNewMember 12,
security=attach_own_keys_for_new_member {
field IdentityList ownIdentities;
}
message GroupKeysAndClose 13,
security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
message OwnKeysOfferer 14, security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
message OwnKeysRequester 15,
security=attach_own_keys_for_new_member {
field IdentityList ownIdentities;
}
// grouped handshake
message NegotiationRequestGrouped 16, security=untrusted {
field TID challenge;
field TID response;
auto Version version;
field TID negotiation;
field bool is_group;
}
message GroupHandshake 17 {
field TID negotiation;
field Hash key;
}
// update group
message GroupKeysUpdate 18, security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
// initiate unled group key reset
message InitUnledGroupKeyReset 19 {
}
message ElectGroupKeyResetLeader 20 {
field TID response;
}
message SynchronizeGroupKeys 21, ratelimit=60 {
}
}
}
{::include excerpts/sync.fsm}
{::include ../shared/fence-line.mkd}

@ -0,0 +1,694 @@
// This file is under BSD License 2.0
// Sync protocol for p≡p
// Copyright (c) 2016-2020, p≡p foundation
// Written by Volker Birk
include ./fsm.yml2
protocol Sync 1 {
// all messages have a timestamp,
// time out and are removed after timeout
fsm KeySync 1, threshold=300 {
version 1, 2;
state InitState {
on Init {
if deviceGrouped {
send SynchronizeGroupKeys;
go Grouped;
}
do newChallengeAndNegotiationBase;
debug > initial Beacon
send Beacon;
go Sole;
}
}
state Sole timeout=off {
on Init {
do showBeingSole;
}
on KeyGen {
debug > key generated
send Beacon;
}
on CannotDecrypt {
debug > cry, baby
send Beacon;
}
on Beacon {
if sameChallenge {
debug > this is our own Beacon; ignore
}
else {
if weAreOfferer {
do useOwnChallenge;
debug > we are Offerer
send Beacon;
}
else /* we are requester */ {
do openNegotiation;
do tellWeAreNotGrouped;
// requester is sending NegotiationRequest
do useOwnResponse;
send NegotiationRequest;
do useOwnChallenge;
}
}
}
// we get this from another sole device
on NegotiationRequest {
if sameChallenge { // challenge accepted
do storeNegotiation;
// offerer is accepting by confirming NegotiationOpen
// repeating response is implicit
send NegotiationOpen;
go HandshakingOfferer;
}
}
// we get this from an existing device group
on NegotiationRequestGrouped {
if sameChallenge { // challenge accepted
do storeNegotiation;
// offerer is accepting by confirming NegotiationOpen
// repeating response is implicit
send NegotiationOpen;
go HandshakingToJoin;
}
}
on NegotiationOpen {
if sameResponse {
debug > Requester is receiving NegotiationOpen
do storeNegotiation;
go HandshakingRequester;
}
else {
debug > cannot approve NegotiationOpen
}
}
}
// handshaking without existing Device group
state HandshakingOfferer timeout=600 {
on Init
do showSoleHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept means init Phase1Commit
on Accept {
do trustThisKey;
go HandshakingPhase1Offerer;
}
// got a CommitAccept from requester
on CommitAcceptRequester {
if sameNegotiation
go HandshakingPhase2Offerer;
}
}
// handshaking without existing Device group
state HandshakingRequester timeout=600 {
on Init
do showSoleHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept means init Phase1Commit
on Accept {
do trustThisKey;
send CommitAcceptRequester;
go HandshakingPhase1Requester;
}
}
state HandshakingPhase1Offerer {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptRequester {
if sameNegotiation {
send CommitAcceptOfferer;
go FormingGroupOfferer;
}
}
}
state HandshakingPhase1Requester {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptOfferer {
if sameNegotiation {
do prepareOwnKeys;
send OwnKeysRequester;
go FormingGroupRequester;
}
}
}
state HandshakingPhase2Offerer {
on Cancel {
send Rollback;
go Sole;
}
on Reject {
send CommitReject;
do disable;
go End;
}
on Accept {
do trustThisKey;
send CommitAcceptOfferer;
go FormingGroupOfferer;
}
}
state FormingGroupOfferer {
on Init {
// we need to keep in memory which keys
// we have before forming a new group
do prepareOwnKeys;
do backupOwnKeys;
}
on Cancel {
send Rollback;
go Sole;
}
on Rollback
go Sole;
on OwnKeysRequester {
if sameNegotiationAndPartner {
do saveGroupKeys;
do receivedKeysAreDefaultKeys;
// send the keys we had before forming a new group
do prepareOwnKeysFromBackup;
send OwnKeysOfferer;
do showGroupCreated;
go Grouped;
}
}
}
state FormingGroupRequester {
on Cancel {
send Rollback;
go Sole;
}
on Rollback
go Sole;
on OwnKeysOfferer {
if sameNegotiation {
do saveGroupKeys;
do prepareOwnKeys;
do ownKeysAreDefaultKeys;
do showGroupCreated;
go Grouped;
}
}
}
state Grouped timeout=off {
on Init {
do newChallengeAndNegotiationBase;
do showBeingInGroup;
}
on CannotDecrypt {
debug > cry, baby
send SynchronizeGroupKeys;
}
on SynchronizeGroupKeys {
do prepareOwnKeys;
send GroupKeysUpdate;
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
on KeyGen {
do prepareOwnKeys;
send GroupKeysUpdate;
}
on Beacon {
do openNegotiation;
do tellWeAreGrouped;
do useOwnResponse;
send NegotiationRequestGrouped;
do useOwnChallenge;
}
on NegotiationOpen {
if sameResponse {
do storeNegotiation;
do useThisKey;
send GroupHandshake;
go HandshakingGrouped;
}
else {
debug > cannot approve NegotiationOpen
}
}
on GroupHandshake {
do storeNegotiation;
do storeThisKey;
go HandshakingGrouped;
}
on GroupTrustThisKey {
if fromGroupMember // double check
do trustThisKey;
}
on LeaveDeviceGroup {
send InitUnledGroupKeyReset;
do disable;
do resetOwnKeysUngrouped;
}
on InitUnledGroupKeyReset {
debug > unled group key reset; new group keys will be elected
do useOwnResponse;
send ElectGroupKeyResetLeader;
go GroupKeyResetElection;
}
}
state GroupKeyResetElection {
on ElectGroupKeyResetLeader {
if sameResponse {
// the first one is from us, we're leading this
do resetOwnGroupedKeys;
go Grouped;
}
else {
// the first one is not from us
go Grouped;
}
}
}
// sole device handshaking with group
state HandshakingToJoin {
on Init
do showJoinGroupHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Sole;
}
on Rollback {
if sameNegotiation
go Sole;
}
// Reject is CommitReject
on Reject {
send CommitReject;
do disable;
go End;
}
on CommitAcceptForGroup {
if sameNegotiation
go HandshakingToJoinPhase2;
}
on CommitReject {
if sameNegotiation {
do disable;
go End;
}
}
// Accept is Phase1Commit
on Accept {
do trustThisKey;
go HandshakingToJoinPhase1;
}
}
state HandshakingToJoinPhase1 {
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Sole;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
do disable;
go End;
}
}
on CommitAcceptForGroup {
if sameNegotiation {
send CommitAccept;
go JoiningGroup;
}
}
}
state HandshakingToJoinPhase2 {
on Cancel {
send Rollback;
go Sole;
}
on Reject {
send CommitReject;
do disable;
go End;
}
on Accept {
do trustThisKey;
send CommitAccept;
go JoiningGroup;
}
}
state JoiningGroup {
on Init {
// we need to keep in memory which keys
// we have before joining
do prepareOwnKeys;
do backupOwnKeys;
}
on GroupKeysForNewMember {
if sameNegotiationAndPartner {
do saveGroupKeys;
do receivedKeysAreDefaultKeys;
// send the keys we had before joining
do prepareOwnKeysFromBackup;
send GroupKeysAndClose;
do showDeviceAdded;
go Grouped;
}
}
}
state HandshakingGrouped {
on Init
do showGroupedHandshake;
// Cancel is Rollback
on Cancel {
send Rollback;
go Grouped;
}
on Rollback {
if sameNegotiation
go Grouped;
}
// Reject is CommitReject
on Reject {
send CommitReject;
go Grouped;
}
on CommitReject {
if sameNegotiation
go Grouped;
}
// Accept is Phase1Commit
on Accept {
do trustThisKey;
go HandshakingGroupedPhase1;
}
on GroupTrustThisKey {
if fromGroupMember { // double check
do trustThisKey;
if sameNegotiation
go Grouped;
}
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
}
state HandshakingGroupedPhase1 {
on Init {
send GroupTrustThisKey;
send CommitAcceptForGroup;
}
on Rollback {
if sameNegotiation {
do untrustThisKey;
go Grouped;
}
}
on CommitReject {
if sameNegotiation {
do untrustThisKey;
go Grouped;
}
}
on CommitAccept {
if sameNegotiation {
do prepareOwnKeys;
send GroupKeysForNewMember;
do showDeviceAccepted;
go Grouped;
}
}
on GroupTrustThisKey {
if fromGroupMember // double check
do trustThisKey;
}
on GroupKeysUpdate {
if fromGroupMember // double check
do saveGroupKeys;
}
on GroupKeysAndClose {
if fromGroupMember { // double check
// do not save GroupKeys as default keys; key data is
// already imported
go Grouped;
}
}
}
external Accept 129;
external Reject 130;
external Cancel 131;
// beacons are always broadcasted
message Beacon 2, type=broadcast,
ratelimit=10, security=unencrypted {
field TID challenge;
auto Version version;
}
message NegotiationRequest 3, security=untrusted {
field TID challenge;
field TID response;
auto Version version;
field TID negotiation;
field bool is_group;
}
message NegotiationOpen 4, security=untrusted {
field TID response;
auto Version version;
field TID negotiation;
}
message Rollback 5, security=untrusted {
field TID negotiation;
}
message CommitReject 6, security=untrusted {
field TID negotiation;
}
message CommitAcceptOfferer 7, security=untrusted {
field TID negotiation;
}
message CommitAcceptRequester 8, security=untrusted {
field TID negotiation;
}
message CommitAccept 9, security=untrusted {
field TID negotiation;
}
message CommitAcceptForGroup 10, security=untrusted {
field TID negotiation;
}
// default: security=trusted
// messages are only accepted when coming from the device group
message GroupTrustThisKey 11 {
field Hash key;
field TID negotiation;
}
// trust in future
message GroupKeysForNewMember 12,
security=attach_own_keys_for_new_member {
field IdentityList ownIdentities;
}
message GroupKeysAndClose 13,
security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
message OwnKeysOfferer 14, security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
message OwnKeysRequester 15,
security=attach_own_keys_for_new_member {
field IdentityList ownIdentities;
}
// grouped handshake
message NegotiationRequestGrouped 16, security=untrusted {
field TID challenge;
field TID response;
auto Version version;
field TID negotiation;
field bool is_group;
}
message GroupHandshake 17 {
field TID negotiation;
field Hash key;
}
// update group
message GroupKeysUpdate 18, security=attach_own_keys_for_group {
field IdentityList ownIdentities;
}
// initiate unled group key reset
message InitUnledGroupKeyReset 19 {
}
message ElectGroupKeyResetLeader 20 {
field TID response;
}
message SynchronizeGroupKeys 21, ratelimit=60 {
}
[...]
}
[...]
}
Loading…
Cancel
Save