This algorithm should serve as a guidance for implementing the XMPP Extension Protocol (XEP) Automatic Trust Management (ATM).
Term | Definition |
---|---|
AND |
logical and (∧ ) |
OR |
logical or (∨ ) |
! |
logical not (¬ ) |
// |
comment |
<term> |
placeholder which must be replaced by a real term |
(<termA> , <termB> ) |
map / associative array of <termA> and <termB> |
message | XMPP message |
key | public long-term key |
bare JID | <user>@<server> |
XMPP URI | xmpp:<bare-jid>?query-type;<key-1>=<value-1>;<key-2>=<value-2>;...;<key-N>=<value-n> |
trust message URI | xmpp:<bare-jid>?trust-message;encryption=<encryption-namespace>;trust=<key-fingerprint-1>;trust=<key-fingerprint-2>;<...>;trust=<key-fingerprint-n>;...>distrust=<key-fingerprint-n+1>;distrust=<key-fingerprint-n+2>;...;distrust=<key-fingerprint-n+m> |
encryptionNamespace | namespace of the key's encryption protocol |
sender | sender of the trust message (bare JID) |
senderFingerprint | fingerprint of the sender's key |
recipient | recipient of the trust message (bare JID) |
account | the user's own account |
ownJid | the account's JID (bare JID) |
contact | a user's contact (bare JID) |
contacts | the user's contacts (bare JIDs) |
owner | owner of keys represented by their fingerprints in trust message (bare JID, jid attribute in trust message element <key-owner/> ) |
owners | multiple owners |
fingerprintsOfAuthenticatedKeysOfContact | fingerprints of authenticated keys of the corresponding contact |
fingerprintsOfAuthenticatedKeysOfOwner | fingerprints of authenticated keys of the corresponding owner |
fingerprints | fingerprints contained in trust message |
fingerprintsForAuthentication | fingerprints in <trust/> element |
fingerprintsForDistrusting | fingerprints in <distrust/> element |
fingerprintsForTrustAction | fingerprints used to authenticate or distrust their corresponding keys |
storage | local storage for data (e.g., a database) |
trust | trust in key (true for authentication, false for distrusting) |
A key can have exactly one of the following trust levels:
- untrusted
- trusted
- manually trusted (e.g., by clicking a button)
- automatically trusted (e.g., by the client for all keys of a bare JID until one of it is authenticated)
- trusted by manual authentication / manually authenticated (e.g., by QR code scanning)
- trusted by automatic authentication / automatically authenticated (e.g., by ATM)
A trust message can be represented by an XMPP URI which can be shared as a QR code. Such a QR code can be scanned by persons who trust the QR code author to authenticate or distrust the keys corresponding to the fingerprints in the trust message.
// URI for Authentication
if (there are authenticated keys with fingerprints of owner for encryption)
return createTrustMessageUri(owner, fingerprints, encryption, true)
// URI for Distrusting
if (there are untrusted keys with fingerprints of owner for encryption)
return createTrustMessageUri(owner, fingerprints, encryption, false)
Attention: The user should only use a trust message URI from a trusted source since that source is able to initiate an authentication or revocation for keys which do not belong to it.
if (
input is XMPP URI
AND XMPP URI is URI of trust message
AND user confirmed to use that URI for authenticating or distrusting the keys of the owner specified in the URI
)
authenticate(owner, fingerprintsForAuthentication, true)
distrust(owner, fingerprintsForDistrusting, true)
An XMPP message is a trust message if it has a trust message structure. ATM uses encrypted trust messages.
if (
message is signed by a signing mechanism
AND message is encrypted
AND message has trust message structure
AND trust message is intended for ATM (i.e., the 'usage' attribute contains ATM's namespace)
)
for (owner in owners)
if (sender is ownJid OR sender is owner)
if (key of senderFingerprint is authenticated)
authenticate(owner, fingerprintsForAuthentication, false)
distrust(owner, fingerprintsForDistrusting, false)
else
cacheTrustMessageData(owner, fingerprintsForAuthentication, senderFingerprint, true)
cacheTrustMessageData(owner, fingerprintsForDistrusting, senderFingerprint, false)
uri = "xmpp:" + owner + "?trust-message;encryption=" + encryptionNamespace
if (trust)
key = "trust"
else
key = "distrust"
for (fingerprint in fingerprints)
uri = uri + ";" + key + "=" + fingerprint
return uri
If only the trust levels untrusted and trusted instead of also authenticated should be used, it is required to check if the current authentication is the first one. If it is the first one, the distrusting of all keys that are not yet authenticated will only happen at the first time. If a user manually trusts a key afterwards, that one will be seen as authenticated.
for (fingerprint in fingerprints)
if (key of fingerprint is in storage)
if (key of fingerprint belongs to owner AND key of fingerprint is not authenticated)
mark key of fingerprint as authenticated
add fingerprint to fingerprintsForTrustAction
authenticateOrDistrustWithCachedTrustMessageData(fingerprint)
else
preAuthenticate(owner, fingerprint)
if (fingerprintsForTrustAction has at least one fingerprint)
if (there is at least one automatically trusted key of owner OR (only needed if trust level *authenticated* is not used) this is the first authentication for owner)
distrust all keys of owner which are not yet authenticated
if (sendTrustMessage)
sendTrustMessage(owner, fingerprintsForTrustAction, true)
for (fingerprint in fingerprints)
if (key of fingerprint is in storage)
if (key of fingerprint belongs to owner AND key of fingerprint is trusted)
mark key of fingerprint as untrusted
add fingerprint to fingerprintsForTrustAction
deleteTrustMessageDataForSender(fingerprint)
else
preDistrust(owner, fingerprint)
if (fingerprintsForTrustAction is not empty AND sendTrustMessage)
sendTrustMessage(owner, fingerprintsForTrustAction, false)
// Authentication
authenticateOrDistrustWithCachedTrustMessageData(senderFingerprint, true)
// Distrusting
authenticateOrDistrustWithCachedTrustMessageData(senderFingerprint, false)
for (owner, fingerprints) in loadTrustMessageData(senderFingerprint, trust))
for (fingerprint in fingerprints)
add fingerprint to fingerprintsForTrustAction
deleteTrustMessageDataForFingerprint(fingerprint)
if (trust)
authenticate(owner, fingerprintsForTrustAction, false)
else
distrust(owner, fingerprintsForTrustAction, false)
for (fingerprint in fingerprints)
if (trust message data for owner, fingerprint, senderFingerprint, trust exists)
return
if (trust message data for owner, fingerprint, senderFingerprint, !trust exists)
update data in storage for owner, fingerprint, senderFingerprint with trust
return
if (trust message data for owner, fingerprint, !trust exists)
delete data in storage for owner, fingerprint
insert trust message data into storage for owner, fingerprint, senderFingerprint, trust
return (owners, fingerprints) from storage for matching senderFingerprint and trust
delete data from storage for matching fingerprint
delete data from storage for matching senderFingerprint
add owner and fingerprint to storage so that corresponding keys which are added later are automatically authenticated
add owner and fingerprint to storage so that corresponding keys which are added later are automatically distrusted
if (owner is ownJid)
deliveredViaMessageCarbons = false
for (contact in contacts)
if (contact has at least one authenticated key)
sendTrustMessage(ownJid, fingerprints, trust, contact)
deliveredViaMessageCarbons = true
if (account has at least one authenticated key AND trust)
sendTrustMessage(contact, fingerprintsOfAuthenticatedKeysOfContact, true, ownJid)
if (!deliveredViaMessageCarbons AND fingerprints are less than authenticated keys of account)
sendTrustMessage(ownJid, fingerprints, trust, ownJid)
else
if (account has at least one authenticated key)
sendTrustMessage(owner, fingerprints, true, ownJid)
if (owner has at least one authenticated key AND trust)
sendTrustMessage(ownJid, fingerprintsOfAuthenticatedKeysOfOwner, true, owner)
send a trust message for owner, fingerprints and trust to recipient and copies (via Message Carbons) for own devices only if they have authenticated keys