You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

664 lines
22 KiB

  1. # p≡p KeySync
  2. KeySync is a protocol of the p≡p Sync family. It is defined in
  3. `pEpEngine/sync/sync.fsm`.
  4. The Use Cases of KeySync are:
  5. - to discover other Devices of the same User, which are using the same Accounts
  6. - to form a Device Group with these Devices
  7. - to join an already existing Device Group in case of a new Device
  8. - to share all Own Identities and all Own Keys within the Device Group
  9. ## Sync Communication Channels
  10. p≡p Sync is designed for Communication Channels with the following properties:
  11. - Broadcast: any Message sent will reach all Devices
  12. - Read Protected: while it is not a problem if arbitrary senders can send
  13. Messages to the Communication Channel, it must be impossible for
  14. unauthenticated Devices to read from the Channel.
  15. - Offline Channel: there can be no way of deciding, which Devices are on the
  16. channel and if they're reading or not.
  17. Examples for Sync Communication Channels are an Inbox of an Account or an MQ
  18. Topic.
  19. p≡p Sync is requiring at least one common Communication Channel between all
  20. Devices in a Device Group.
  21. ## Graphical representation of the KeySync Finite State Machine
  22. ![Finite State Machine for KeySync](/keysync.svg)
  23. ## State Machine Model
  24. The p≡p Sync protocols are implemented using a State Machine each. The State
  25. Machine Model for p≡p Sync is defined in `pEpEngine/sync/sync.fsm`. This file
  26. is written using the [YML2 tool chain](https://fdik.org/yml). The syntax of the
  27. Model is defined by [declaring functions](https://fdik.org/yml/features#decl)
  28. in `pEpEngine/sync/fsm.yml2`.
  29. ##### Syntax
  30. decl protocol @name (id, threshold=10);
  31. ##### Definition
  32. protocol Sync 1
  33. Defines the Sync Protocol Family with ID 1.
  34. ### State Machine
  35. KeySync is defined as Finite State Machine.
  36. ##### Syntax
  37. decl fsm @name (id, threshold=10);
  38. ##### Definition
  39. fsm KeySync 1, threshold=300
  40. Defines the State Machine for the KeySync Protocol with ID 1 and a Threshold of
  41. 300 seconds until a the timeout Event occurs.
  42. ### States
  43. A State Machine is always in one State.
  44. ##### Syntax
  45. decl state @name (timeout=on);
  46. #### InitState
  47. state InitState
  48. When a State Machine is initialized, it is in InitState.
  49. #### Stable States
  50. The State Machine of KeySync has two Stable States, which are not timing out:
  51. ##### Sole
  52. state Sole timeout=off
  53. KeySync is in this State while the Device is not yet member of a Device Group.
  54. ##### Grouped
  55. state Grouped timeout=off
  56. KeySync is in this State while the Device is member of a Device Group.
  57. #### Transitional States
  58. All other states are Transitional States. Those are documented in the [Use
  59. Cases chapter](#use-cases).
  60. ### Events
  61. While being in a State it can happen that an Event occurs. In this case the
  62. corresponding Event Handler will be executed.
  63. ##### Syntax
  64. decl event @name, on is event;
  65. #### Init Event
  66. When the State Machine transitions to a State the Init event is happening to
  67. this State. If an Init Event Handler is present for this State this Event
  68. Handler is called. The Event Handler may contain [Conditions](#conditions),
  69. [Actions](#actions), sending of [Messages](#messages) and
  70. [Transitions](#transitions). All States can have a handler for an Init event,
  71. including the `InitState`.
  72. ##### Sample
  73. state InitState { on Init { if deviceGrouped { send SynchronizeGroupKeys;
  74. go Grouped; } go Sole; } }
  75. #### Message Event
  76. If a Sync Message arrives through the Network then the Event with the name of
  77. the Message is occuring.
  78. ##### Sample
  79. In this example an Event Handler is defined, which is executed when a Beacon
  80. Message arrives:
  81. on Beacon { do openNegotiation; do tellWeAreGrouped; do useOwnResponse;
  82. send NegotiationRequestGrouped; do useOwnChallenge; }
  83. #### Signaled Events
  84. Events, which don't share their name with a Message, are being signaled from
  85. engine code.
  86. ##### Sample
  87. The KeyGen Event has no corresponding Message. Therefore, it is not occuring
  88. when a Sync Message arrives but when it is signaled from code:
  89. on KeyGen { do prepareOwnKeys; send GroupKeysUpdate; }
  90. The signalling can be done by calling `signal_Sync_event()`:
  91. // call this if you need to signal an external event // caveat: the
  92. ownership of own_identities goes to the callee
  93. PEP_STATUS signal_Sync_event( PEP_SESSION session, Sync_PR fsm, int event,
  94. identity_list *own_identities);
  95. ##### Sample
  96. In this example the KeyGen event is signaled to KeySync when a new Own Key is
  97. generated:
  98. signal_Sync_event(session, Sync_PR_keysync, KeyGen, NULL);
  99. #### External Event IDs
  100. If Events are part of an API then their IDs must be well defined. Therefore, it
  101. is possible to define such IDs in the State Machine.
  102. ##### Syntax
  103. decl external @name (id);
  104. ##### Sample
  105. external Accept 129;
  106. ### Transitions
  107. To switch to another State it is possible to write a Transition into an Event
  108. Handler.
  109. ##### Syntax
  110. decl transition @target, go is transition;
  111. ##### Sample
  112. In this example there are two Transitions, one to State Grouped and one to
  113. State Sole:
  114. on Init { if deviceGrouped { send SynchronizeGroupKeys; go Grouped; } go
  115. Sole; }
  116. ### Messages
  117. KeySync is a Network Protocol, which is implemented using Sync Messages. The
  118. Sync Messages for KeySync are defined at the end of the Finite State Machine in
  119. `pEpEngine/sync/sync.fsm`.
  120. The wire format of Sync Messages is defined in
  121. [ASN.1](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One), see
  122. `pEpEngine/asn.1/keysync.asn1`, using
  123. [PER](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Packed_Encoding_Rules).
  124. Sync Messages are transported as Attachments to p≡p Messages. Hence they're
  125. transported by the same Transports, which are transporting p≡p Messages. Some
  126. Sync Messages must be sent in copy on all Transports. Others are transported on
  127. the Active Transport only. The Active Transport is the Transport, on which the
  128. last Sync Message was received.
  129. Each Sync Message has a name and an ID. There is different types of Messages:
  130. - `type=broadcast` for Messages, which are meant to be copied on all Transports
  131. - `type=anycast` for Messages, which are meant to be sent on the Active
  132. Transport only
  133. Each Sync Message has a Security Context. The available Security Contexts are:
  134. - `security=unencrypted`: send and receive as unencrypted but signed Sync
  135. Message
  136. - `security=untrusted`: only accept when encrypted and signed
  137. - `security=trusted` (default): only accept when coming over a Trusted Channel
  138. and when originating from the Device Group
  139. - `security=attach_own_keys_for_new_member`: like `security=trusted` but attach
  140. all Own Keys for a new Member of the Device Group
  141. - `security=attach_own_keys_for_group`: like `security=trusted` but atttach all
  142. Own Keys for other Device Group Members.
  143. A Sync Message can have a Rate Limit `ratelimit=<numeric>`. That means it is
  144. only possible to send out one message each `<numeric>` seconds. A Rate Limit of
  145. 0 means no Rate Limit checking.
  146. ##### Syntax
  147. decl message @name (id, type=anycast, security=trusted, ratelimit=0);
  148. ##### Sample
  149. message Beacon 2, type=broadcast, ratelimit=10, security=unencrypted {
  150. field TID challenge; auto Version version; }
  151. #### Fields
  152. A Sync Message can have Fields. There is two types of fields: automatically
  153. calculated fields, defined with the `auto` keyword, and fields, which are
  154. copied in and out from the I/O buffer, marked with the `fields` keyword.
  155. The wire format of the fields is depending on their type. The types are defined
  156. in `pEpEngine/asn.1/pEp.asn1`. Additionally, the two basic types `bool` (ASN.1:
  157. BOOLEAN) and `int` (ASN.1: INTEGER) are supported.
  158. ##### Syntax
  159. decl field @type @name; decl auto < field >;
  160. ##### Sample for an `auto` field:
  161. auto Version version;
  162. This field will be filled with the p≡p Sync Protocol version. The `Version`
  163. type is the only automatically calculated type yet.
  164. ##### Sample for an field coming from I/O buffer
  165. field TID challenge;
  166. #### I/O Buffer
  167. There is an I/O Buffer for all Fields, which are occuring in Messages. All
  168. Messages share this I/O buffer. Fields with the same name share one space in
  169. the I/O Buffer. Hence, the I/O Buffer is built as superset of all Fields'
  170. buffers.
  171. #### Sending
  172. Sending is being done by:
  173. 1. Calculating all `auto` Fields and copying the result into the I/O Buffer
  174. 1. Loading all Fields of the Message from I/O Buffer
  175. 1. Creating a Sync Message
  176. 1. Creating a transporting p≡p Message by attaching the Sync Message using Base
  177. Protocol
  178. 1. Calling `messageToSend()` with this p≡p Message
  179. ##### Syntax
  180. decl send @name;
  181. ##### Sample
  182. send SynchronizeGroupKeys;
  183. #### Receiving
  184. When a Message is being received the field values are being copied into the I/O
  185. Buffer and the corresponding [Event](#events) is being signaled.
  186. ### Conditions
  187. Conditions are implemented in `pEpEngine/sync/cond_act_sync.yml2` with the
  188. keyword `condition`. All implemented Conditions can be used in any Sync
  189. Protocol. A [dangling else](https://en.wikipedia.org/wiki/Dangling_else) and
  190. [nesting](https://en.wikipedia.org/wiki/Nesting_(computing)) of Conditions are
  191. supported. Hence, Conditions can contain all elements, which can be contained
  192. by Event Handlers, too. All Conditions can either be true or false on success,
  193. or they fail and are bringing the State Machine into an error state, and the
  194. State Machine will be initialized.
  195. ##### Syntax
  196. decl condition @name, if is condition; decl else;
  197. ##### Sample
  198. Checking the Condition `sameResponse` and executing Actions and Transitions
  199. depending on its result:
  200. if sameResponse { // the first one is from us, we're leading this do
  201. resetOwnGroupedKeys; go Grouped; } else { // the first one is not from us
  202. go Grouped; }
  203. The implemented Conditions are:
  204. #### condition deviceGrouped
  205. True if the Device is already member of a Device Group. This is determined by
  206. checking if there are Group Keys already.
  207. #### condition fromGroupMember
  208. For double checking. True is the incoming Sync Message is coming from a Device
  209. Group member.
  210. #### condition keyElectionWon
  211. True if our Own Keys are going to be used as Group Keys. False if the Own Keys
  212. of the partner will be the Group Keys. Calculated by comparing if the FPR of
  213. the Sender Key of the partner is greater than our Default Key for the Account,
  214. which is being used as Active Transport.
  215. #### condition sameChallenge
  216. True if the Challenge of the incoming Sync Message is identical to the
  217. Challenge of the Device. In this case this was a Sync Message sent by the
  218. Device itself.
  219. #### condition sameNegotiation
  220. True if the Negotiation of the incoming Sync Message is identical to the
  221. Negotiation the Device is in. In this case the incoming Sync Message is part of
  222. the same Negotiation.
  223. #### condition sameNegotiationAndPartner
  224. True if the Negotiation of the incoming Sync Message is identical to the
  225. Negotiation the Device is in and the partner did not change. In this case the
  226. incoming Sync Message is part of the same Negotiation coming from the expected
  227. Device.
  228. #### condition sameResponse
  229. True if the Response of the incoming Sync Message is identical to the Response
  230. of the Device. In this case the Response was correctly echoed.
  231. #### condition weAreOfferer
  232. True if the Challenge of the incoming Sync Message is greater than the
  233. Challenge of the Device. Otherwise we're Requester.
  234. ### Actions
  235. Actions are implemented in `pEpEngine/sync/cond_act_sync.yml2` with the keyword
  236. `action`. All implemented Actions can be used in any Sync Protocol. Actions are
  237. unconditionally executing the code of their implementation. All Actions may
  238. fail. In this case they're bringing the State Machine into an error state, and
  239. the State Machine will be initialized.
  240. ##### Syntax
  241. decl action @name, do is action;
  242. ##### Sample
  243. do useOwnChallenge;
  244. #### action backupOwnKeys
  245. Make a backup of all Own Keys.
  246. #### action disable
  247. Diable Sync and shut down the State Machine.
  248. #### action newChallengeAndNegotiationBase
  249. A new Challenge and a new Response will be computed randomly. Both are copied
  250. into the I/O Buffer. The Negotiation Base is being computed randomly.
  251. #### action openNegotiation
  252. Key and Identity of the partner are being cleared. The Negotiation ID is being
  253. calculated by the Negotiation Base XOR the Challenge of the partner.
  254. #### action ownKeysAreDefaultKeys
  255. Flag Default Keys of Own Identities as Group Keys.
  256. #### action prepareOwnKeys
  257. Write list of Own Identities into the I/O Buffer and load list of Own Keys into
  258. the Device state.
  259. #### action prepareOwnKeysFromBackup
  260. Restore the formerly backed up Own Keys into the I/O Buffer.
  261. #### action receivedKeysAreDefaultKeys
  262. Set the received Own Keys as Default Keys for the Own Identities.
  263. #### action resetOwnGroupedKeys
  264. Do a KeyReset on Own Group Keys.
  265. #### action resetOwnKeysUngrouped
  266. Do a KeyReset on all Own Keys.
  267. #### action saveGroupKeys
  268. Load Own Identities from the I/O Buffer and store them as Own Identities.
  269. #### action showBeingInGroup
  270. Signal `SYNC_NOTIFY_IN_GROUP` to the App.
  271. #### action showBeingSole
  272. Signal `SYNC_NOTIFY_SOLE` to the App.
  273. #### action showDeviceAccepted
  274. Signal `SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED` to the App.
  275. #### action showDeviceAdded
  276. Signal `SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED` to the App.
  277. #### action showJoinGroupHandshake
  278. Signal `SYNC_NOTIFY_INIT_ADD_OUR_DEVICE` to the App.
  279. #### action showGroupCreated
  280. Signal `SYNC_NOTIFY_ACCEPTED_GROUP_CREATED` to the App.
  281. #### action showGroupedHandshake
  282. Signal `SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE` to the App.
  283. #### action showSoleHandshake
  284. Signal `SYNC_NOTIFY_INIT_FORM_GROUP` to the App.
  285. #### action storeNegotiation
  286. The Negotiation in the I/O Buffer is being stored for the Device. The Sender
  287. FPR and partner's Identity are both stored for later comparison.
  288. #### action storeThisKey
  289. Load the Sender Key of the partner from the I/O Buffer and store it for later
  290. use.
  291. #### action tellWeAreGrouped
  292. Set the `is_grouped` Field in the I/O Buffer to true.
  293. #### action tellWeAreNotGrouped
  294. Set the `is_grouped` Field in the I/O Buffer to false.
  295. #### action trustThisKey
  296. Trust the formerly stored Key of the partner. Load this Key into the I/O
  297. Buffer.
  298. #### action untrustThisKey
  299. Revoke Trust from the formerly stored Key of the partner. Clear the Key in the
  300. I/O Buffer.
  301. #### action useOwnChallenge
  302. The Challenge of the Device is being copied into the I/O Buffer.
  303. #### action useOwnResponse
  304. The Response of the Device is being copied into the I/O Buffer.
  305. #### action useThisKey
  306. Copy the stored Sender Key of the partner into the I/O Buffer.
  307. ## Use Cases
  308. ### Device Discovery
  309. If there is more than one Device using the same Sync Channel (i.e. the same
  310. Inbox in one or more Accounts, respectively) then p≡p Sync is there to detect
  311. the other Devices. Therefore, a Device, which is in state Sole, is sending a
  312. Beacon Message, so it can be detected by a second Sole Device or by Devices,
  313. which are already forming a Device Group.
  314. #### Relating Beacons
  315. To make it distinguishable, which Device is sending which Beacon, Beacons have
  316. the Field `challenge`. This field is of type `TID` (transaction ID), which is
  317. defined as UUID version 4 variant 1: a completely random UUID (see
  318. `pEpEngine/asn.1/pEp.asn1`).
  319. The `challenge` is initialized with new random data whenever one of the two
  320. Stable States (Sole or Grouped) are being reached. It is a pseudonym for the
  321. Device. The initialization takes place by executing the Action
  322. `newChallengeAndNegotiationBase`.
  323. #### The Handshake
  324. By reading a Beacon, which does not deliver the own `challenge`, a Device can
  325. learn of a new other Device. Beacons are then answered with a
  326. NegotiationRequest Message. This message is repeating the Beacon's `challenge`
  327. and adding an own `response`, which is again a randomly chosen `TID`, and again
  328. a pseudonym. Own NegotiationRequest Messages can be identified and ignored by
  329. the value of the `response`. Additionally, a suggestion for a transaction ID
  330. for a `negotiation` about forming a Device Group or joining an existing Device
  331. group is being sent, together with the field `is_group` to determine between
  332. the two cases.
  333. When reading the NegotiationRequest of another Device, which is repeating the
  334. own `challenge` a Device learns that it was detected by another Device. It then
  335. is answering with a NegotiationOpen Message by repeating the `response`
  336. pseudonym of the other device and the transaction ID for the `negotiation` to
  337. signal that it is aware of the other Device and ready to execute the
  338. `negotiation` process.
  339. The three messages Beacon, NegotiationRequest and NegotiationOpen are
  340. fulfilling the pattern of a [three way
  341. handshake](https://en.wikipedia.org/wiki/Handshaking). At the same time
  342. NegotiationOpen is opening a [distributed
  343. transaction](https://en.wikipedia.org/wiki/Distributed_transaction), the
  344. Negotiation.
  345. ### Forming a Device Group by two Sole Devices
  346. In case there is no Device Group existing yet, then two Sole devices can form
  347. one. There is an extra problem then: the symmetry of the situation. Which
  348. Device does have the role of sending out Beacons and which has the role of
  349. answerng with a NegotiationRequest Message? This must be decided first. Hence
  350. there are two roles a Device can go into: the Offerer, who is sending the
  351. Beacon, and the Requester, who is answering with a NegotiationRequest Message.
  352. #### Deciding Roles
  353. Both Devices have to decide their role independently from each other, and it
  354. must be guaranteed that the decision is correspondent on both sides,
  355. respectively.
  356. To make this possible the criterion to decide whether a Device is Offerer or
  357. Requester there is the Condition `weAreOfferer`. The Device is Offerer if the
  358. `challenge` of the other Device is greater than its own `challenge`, otherwise
  359. it is Requester.
  360. The decision is being made on a Beacon Message arriving. Then the Device is
  361. knowing both Challenge TIDs.
  362. #### Starting the Negotiation as Offerer
  363. If the Device is Offerer and it gets a Beacon it may be the case that the
  364. former own Beacon timed out so the other Device couldn’t see it. Hence another
  365. Beacon is sent out to make sure the other Device can see that we’re Offerer.
  366. Being Offerer the Device is waiting for a NegotiationRequest coming from the
  367. Requester. When a NegotiationRequest is arriving the Device is checking if the
  368. own `challenge` was repeated. By doing so it is checking if the Requester is
  369. authenticated and can read the Channel. In case it is storing the `negotiation`
  370. TID for further use. From then on it is basing its communication on this TID
  371. while it is in this Negotiation. It tells this to the other Device by sending
  372. the NegotiationOpen Message repeating the `response`. There is no Action to
  373. repeat the `response`, because repeating what is in the I/O Buffer is the
  374. default. Then it is transitioning to the State HandshakingOfferer, which is a
  375. Transitional State to start the Handshake process.
  376. #### Starting the Negotiation as Requester
  377. If the Device is Sole and Requester the flag `is_grouped` is cleared in the I/O
  378. Buffer by executing `tellWeAreNotGrouped` to signal its Sole State to the
  379. Offerer. Executing `useOwnResponse` is copying the own Response TID into the
  380. I/O Buffer.
  381. Executing the Action `openNegotiation` is calculating the Negotiation TID as
  382. Challenge of the other Device XOR Negotiation Base. By doing so each possible
  383. partner is having its own Negotiation ID in case multiple Sole Devices are
  384. active at the same time. Then the Message NegotiationRequest is being sent out.
  385. After sending the NegotiationRequest the value of the `challenge` in the I/O
  386. Buffer is reverted to the own Challenge TID to answer other Beacons, which may
  387. arrive from other Devices.
  388. The Requester is then waiting for the NegotiationOpen Message from the Offerer.
  389. It is checking if the `response` was correctly repeated. By doing so it is
  390. checking if the Offerer is authenticated and can read the Channel. The
  391. Requester is storing the `negotiation` TID for further use. The Device is
  392. transitioning to the Transitional State HandshakingRequester to start the
  393. Handshake process.
  394. #### Handshaking with two Sole Devices
  395. Each Device is waiting for two Events, which both must happen: the User
  396. must Accept the Handshake on the Offerer Device and the User must Accept the
  397. Handshake on the Requester Device. Only if both Accepts where received the
  398. Handshake is accpeted.
  399. The Offerer is sending the Message CommitAcceptOfferer in case it gets
  400. signalled Accept from the User, so the Requester gets informed about this.
  401. Accordingly, the Requester is sending CommitAcceptRequester in case it is
  402. getting signalled Accept from its User.
  403. The sending of CommitAcceptOfferer and CommitAcceptRequester are not arbitrary
  404. in sequence, though. To keep the wanted asymmetry the Offerer is only sending
  405. CommitAcceptOfferer after it was receiving CommitAcceptRequester AND it was
  406. signalled the Accept Event by the User. The Requester is sending
  407. CommitAcceptRequester immediately after it got signalled the Accept Event from
  408. the User. As a result the CommitAcceptRequester Message is always sent before
  409. the CommitAcceptOfferer is being sent.
  410. The Negotiation is considered committed with result Accept if and only if both
  411. Commit Messages where received. This is fulfilling the pattern of the
  412. [Two-phase commit
  413. protocol](https://en.wikipedia.org/wiki/Two-phase_commit_protocol).
  414. #### In case of Reject or Cancel
  415. If the User selects Reject on Offerer or Requester, then the CommitReject
  416. Message is being sent and p≡p Sync is being disabled. If the CommitReject
  417. Message is received because the User selected Reject on the other Device, p≡p
  418. Sync is disabled, too.
  419. The Negotiation is considered committed with result Reject if Offerer OR
  420. Requester sent CommitReject. This is a derivate of the Two-phase commit
  421. protocol.
  422. In case the User selects Cancel then the Rollback Message is being sent, and
  423. the Device is transitioned to State Sole. The Negotiation is then cancelled,
  424. but a next Negotiation can happen after this. In case a Rollback Message is
  425. being received then the Device is transitioned to State Sole. The Negotiation
  426. is then cancelled, but a next Negotiation can happen after this.
  427. The Rollback is fulfilling the pattern of the Two-phase commit protocol.
  428. ### Joining an already existing Device Group
  429. ### Sharing of Own Identities and Own Keys in a Device Group