Engine/UserPseudonymity
The problem
Users may choose to use a different pseudonym for a different identity, and this should not only be kept consistent in their communication, but is a core privacy issue. A gamer’s leisuretime persona, FurryBob420
, for example, should not leak information when she sends professional mails as Alice Spivak
to her child’s school. The previous implementation always kept one canonical username (updated in various ways, but still potentially leakable between identities when not specified in an input identity struct), which made such leakage possible.
This description aims to partially specify new means to allow consistency of usernames by identity. (From the user standpoint at the app level, the p≡p application user identifies communication partners by using the contact management of her/his messaging app, so any mapping of such names to identities, particularly for the own user, will be done there (see caveat below regarding partner users).
Glossary
msg
: a p≡pmessage
struct- addressees: all identities of
msg.to
andmsg.cc
as listed on themsg
struct - inner message: the rfc822 message contained inside the attachments section of an encrypted incoming or outgoing p≡p message’s payload
- transported message: in case of non-legacy p≡p messages, the inner (actual) message before encryption or after decryption; for other messages (OpenPGP, unencrypted, legacy p≡p), there is no outer message, so this will just be the normal message transmitted
src
: the input message forencrypt_message()
ordecrypt_message()
dst
: the output message forencrypt_message()
ordecrypt_message()
src.from
: indecrypt_message()
, thefrom
identity that is derived directly from the outer (or only) messagedst.from
: indecrypt_message()
, the calculatedfrom
identity; this may, for transport or privacy reasons, differ completely fromsrc.from
when coming from the inner message, or it may be equivalent/the same assrc.from
, in the case of legacy/non-p≡p messages. This is the identity that will be delivered back to the caller ofdecrypt_message()
- set: (in regard to
person.username
andidentity.username
) - save to the management database - deliver: return from a function call
Privacy and security goals
- Avoidance of third-parties being able to map a pseudonym to other pseudonyms or trace a pseudonym back to an actual person, where feasible
- No external party should be able to set/reset an own username/pseudonym
- No external party, other than the verified communications partner, should be able to set/reset the pseudonym for an identity once a reliable channel has been established
- FIXME: This sentence does not make sense. Have asked question in query and will rewrite it once the author replies - until then, I presume this falls under the first sentence ;)
The p≡p User may want to communicate to the Communication Partner using their chosen Pseudonym to not uncover the username in Contact Management.
Solution
Database Storage
- Generally, the username from contact management is stored in
person.username
in the management database. However, since any call to update_identity may set this value, some care needs to be taken to ensure this is either always supposed to be true, or actually IS true. - Depending on the message direction and whether this is an own user, the pseudonym from the transported message is stored in
identity.username
in the management database
API calls
update_identity()
update_identity()
setspeople.username
in all cases.update_identity()
setsidentity.username
only if it is empty.
myself()
myself()
sets identity.username
.
decrypt_message()
- In the case that the message rating is at least reliable,
decrypt_message()
setsidentity.username
from whatever thedst.from
identity (calculated output identity) is decrypt_message()
setsidentity.username
fromsrc.from
in case the message is unprotected and the channel is insecure.decrypt_message()
setsidentity.username
fromsrc.from
in case the message is unprotected and the channel is secure only ifidentity.username
is empty.decrypt_message()
deliversidentity.username
for all addressees ofdst
in case of protected message orsrc
otherwise, without storing them.We can avoid me calling update_identity all over the place here by putting a special get_identity_username function - less DB intensive than update_identity and won’t set anything. But in case there is not one in the DB, do we deliver src., or nothing?
encrypt_message()
encrypt_message()
sets identity.username
for all addressees of src
only where it is empty, respectively. See “known issues”
Usage of username
When rendering an identity for the Transported Message in case identity.username
is set this is used, otherwise if people.username
is set this is used, otherwise no username
is used.
Known issues
- We always choose to use the username sent to us by the most verifiable assertion of identity received by a partner so far. In this scenario, there is little the user can do to keep the partner from setting them up to send undesired username information attached to the partner’s identity to others. Take, for example, the following scenario:
hussidente@huss_for_pres.cat
wants everyone to think DarthMama thinks he should not be elected president, which is, of course, not true. And Hussidente KNOWS DarthMama will mail lots of people with him in CC:. DarthMama’s pseudonym for Hussidente is “Hussidente Maximus”. Hussidente mails DarthMama a mail with fromfrom
name “DON’T VOTE FOR HUSS EVER - I’LL GIVE YOU EUR 100 NOT TO!” DarthMama sends out a mail to a group of colleagues, and suddenly has promised them all 100 Euros not to vote for Hussidente. One can think of worse examples, of course - you could cause someone to inadvertantly abuse you in front of others to get them in trouble. - When rendering an identity for the Outer Message no username should be used, but
identity.username
will be used if set in the first version, because otherwise pEp for Thunderbird cannot work. This must be marked in source code and a bug ticket must be created and the ticket number must be mentioned in source. (p≡p generally protects messages by only allowing confidential information in the inner message.) - Conformance to this spec is fragile - calls to
update_identity()
will have to be managed closely. Please note that adding such calls todecrypt_message()
in particular will change behaviour; tests will be written to detect such problems once specification problems above are resolved.