Engine/Echo Protocol

Introduction and rationale

Echo is a protocol in the Distribution family.

Echo does not deliver any security property: it is only used to initiate TOFU. The Echo protocol in fact partly destroys privacy — which is why it can be switched off, session-wise. It is enabled by default.

Echo allows the first message with content in an exchange to be protected, when it otherwise would not be.


There are only two messages:

  • Ping;
  • Pong.

A communication partner Alice can send a Ping message to a communication partner Bob, usually attaching her sender key. Bob, if he so desires, can reply with a Pong message to Alice, also usually attaching his sender key. Upon reception of Bob’s Pong message Alice is notified.

The Pong message from Bob to Alice can already be encrypted, and so will be any further communication between the two.

There is no requirement for the transport to be reliable or to deliver messages in order. The recipient of a Ping message may chose not to respond with a Pong.

Protocol state and message fields

Echo is a stateless protocol except for the data involved in a challenge/response exchange, and in rate-limitation. The challenge/response machinery only serves to recognise forged Pong messages.

The echo_challange field is a new column of the Identity table in the management database, set to a non-NULL value (a copy of the random UUID which was sent) only for the identities to which we have sent a Ping message.

The only message fields are the challenge in Ping (a copy of which is stored as echo_challenge) and a response in Pong (UUID equal to the challenge in the Ping message to which the Pong message is a reply).

Another new column named last_echo_timestamp exists in the Identity table for the purpose of rate-limiting Echo messages sent by us (with any session, on one device) to the same recipient Identity.

We rate-limit both Ping and Pong messages:

  • we rate-limit Ping messages in order not to send a flood of messages when we are waiting for a response;
  • we rate-limit Pong messages in order to avoid DoS attacks in which the message rate is amplified, which can happen in mailing lists.

The macro PEP_MINIMUM_ECHO_MESSAGES_PERIOD_IN_SECONDS defined in src/echo_api.h defines the minimum time elapsed between Echo messages sent to the same identity from one device.

Engine API

The public API for the Echo protocol is simple.


void config_enable_echo_protocol(PEP_SESSION session,
                                 bool enable);

In the given session, enable or disable the Distribution.Echo protocol: enable iff enable is true. The protocol is enabled by default.


void config_enable_echo_in_outgoing_message_rating_preview(PEP_SESSION session,
                                                           bool enable);

In the given session alter the behaviour of outgoing_message_rating_preview: Ping messages will be sent from it iff enable is true (and if the Echo protocol is enabled). Ping messages from outgoing_message_rating_preview are enabled by default.

Disabling Echo on message rating preview while the Echo protocol is otherwise enabled is intended as a performance optimisation: outgoing_message_rating_preview should execute quickly.

Whenever the Echo protocol is enabled outgoing_message_rating also sends Ping messages to unknown recipients known to be p≡p-using identities (it is possible to recognise some p≡p identities as such thanks to media keys). outgoing_message_rating is allowed to execute more slowly (which is the entire reason for outgoing_message_rating_preview’s existence) and therefore no way of disabling Ping messages from outgoing_message_rating is needed.


The enum type hidden in the definition of sync_handshake_signal has been enriched by a new case, SYNC_NOTIFY_OUTGOING_RATING_CHANGE.

When decrypt_message receives a valid (meaning with the expected response) Pong message it sends a SYNC_NOTIFY_OUTGOING_RATING_CHANGE notification. This is intended for an interactive application displaying a colour for an outgoing message being composed: upon reception of a Pong message the rating, and therefore colour, of the message being composed might change. The application should recompute the rating and display a new colour: thanks to this feature the colour of a message might “spontaneously” change from no-colour to yellow while it is being composed, thanks to a quick Ping/Pong exchange with a new recipient, invisible to the application user.

The fact that notifications unrelated to the Sync protocol are handled under the “SYNC_” or “sync_” namespace is a historical artefact: while notifications were born with the Sync protocol they are no longer limited to it.


Adapter and application developers should be informed about some caveats about SYNC_NOTIFY_OUTGOING_RATING_CHANGE.

Notifications, Engine sessions and threads

The Engine sends this notification by calling s->notifyHandshake, a C function pointer contained in the PEP_SESSION s which was involved in decrypting the Pong message. If the adapter uses one Engine session per thread this means that notifyHandshake will only be called in one thread, and that thread will be the same which decrypted the Pong message — not necessarily the same thread handling the graphical user interface. It is the adapter’s or application’s responsibility to ensure that notifyHandshake is actually set in the correct thread; the Engine has no control over the multiple sessions that may exist across threads in the same memory space.

Adapters can register callbacks for notifications though the Engine function register_sync_callbacks.

Unknown notifications

Not every current application supports SYNC_NOTIFY_OUTGOING_RATING_CHANGE at this time; however this is not a serious problem.

Since applications have always been supposed to ignore unknown notifications the introduction of SYNC_NOTIFY_OUTGOING_RATING_CHANGE does not constitute an incompatible API change.

If notifyHandshake is not set in the appropriate session the Engine will simply not send the notification, while still correctly handling key distribution from the Pong message.

So when an application ignores a SYNC_NOTIFY_OUTGOING_RATING_CHANGE event from the Engine the effect will be the application displaying the outgoing message with a worse colour than it should: in particular an outgoing message being composed might be presented as no-colour instead of yellow.

Unnecessary API functions

There is no API call for directly sending Ping messages; such messages are sent automatically where needed. There is no API call for sending Pong messages either: a Pong message is automatically sent as a reply to Ping when the Distribution.Echo protocol is enabled.

There is no API for handling a Ping message: Ping messages are automatically handled by decrypt_message.

An application may handle Pong messages (after decrypting and, crucially, importing keys) through the SYNC_NOTIFY_OUTGOING_RATING_CHANGE notification.

Protocol use cases

  • When a reliable message is received and some recipients are unknown to us, we automatically send a Ping message to each unknown recipient. This will help retrieving their keys, which will be useful in the event of a message from us to them;
  • Even when we receive an unprotected message we may know, thanks to media keys, that some recipients unknown to us are in fact p≡p-using identities. In that case we send a Ping message to each unknown identity known to use p≡p, which again will be useful in case of future exchanges with them;
  • A Ping message is sent to each recipient of a message being composed who is known to be a p≡p-using identity (thanks to media keys) but is still unknown. If maximum performance is desired one can disable Ping messages from outgoing_message_rating_preview (but not from outgoing_message_rating) through config_enable_echo_in_outgoing_message_rating_preview, described above.
  • also see Docu on Echo and Session

More use cases may be added in the future now that the infrastructure is ready and solid. The internal function send_ping is easy to use.