XEP-Remarks/XEP-0373: OpenPGP for XMPP

Revision as of 10:16, 28 May 2022 by Vanitasvitae (talk | contribs) (→‎XEP Review)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

This is a page for information about XEP-Remarks/XEP-0373: OpenPGP for XMPP, including errata, comments, questions, and implementation experience.

Key publication, notification and retrieval

The XEP has undergone already one change regarding key publication, notification and retrieval of key material. The initial used approach was found to be quite traffic demanding, because the full key data was pushed to interested entities every time they appeared online. Thus it was decided to split the key into metadata and data PubSub/PEP nodes.

While it turned out to work quite well, it is not elegant with regard to the mechanisms the involved protocols provide. From a pure "what the specification describes" pont-of-view, an ideal solution would possibly be to

  • Use a single node per key type (public- / secret-key)
  • Use XEP-0060 "notification only" nodes (configuration value: pubsub#deliver_payloads), which would only push the node id to the subscribed entity (but was only recently implemented in prosody and the feature is not discoverable, most likely because it appears to be mandatory by XEP-0060).
  • Use a timestamp, possibly in XEP-0082 DateTime profile format, as item IDs
  • Use a fixed string for the PubSub/PEP node names (like it is already done right now for the metadata nodes)
  • Use Singleton Node (XEP-0060) for the metadata node, public key node. The option max_items=1 when retrieving the node content is an optional feature not supported by all servers. There is no need to have more than one item in these nodes, there should at any point always only one public key list, one public key per public key node. Force all Clients to publish with the same item id "current" (XEP-0060) to prevent problems with multiple items in the node.
  • Consider to publishing one secret key per item with a item-id=fingerprint instead of concatenating multiple keys together
    • Problems with current XEP behavior:
      - Clients cannot know if their secret key is stored without pulling the payload and looking into it (A bad client could overwrite the key)
      - Clients have to pull from time to time the full secret key node, and look into the payload if their key ist still in storage
    • Upsides with new approach:
      - Clients can efficiently find out with a disco of the node if their secret key is still in storage
      - Clients can efficiently get a list of all secret keys + fingerprints, without pulling the payload and doing gpg operations
      - Clients can then ask the user which secret key should be pulled / they want to use
      - Less likely to run into a stanza size limit
    • Possible Downsides:
      - Clients should make sure to encrypt all secret keys with the same backup code for ease of use (they will have to ask the user for it)
  • Mention that generating the PGP key with a password would lead to multiple password entrys for the user (once to restore the backup from the secret node, then a second time to use the key). To get broad adoption it should be as easy as possible, meaning no password on the key itself. Also it should be discouraged to use an already existing key which is used in other context than IM (like email), rather create a new key just for the IM context. This and the no password suggestion would lead to a much easier implementation because GPG Agent (no password on the key) is out of the picture and you dont have to deal with messages that can not be decrypted instantly but at a later point.

Although there appears to be no direct way to query the PubSub/PEP service if it supports pubsub#deliver_payloads, it may be possible for entities to probe the availability of this feature by attempting to create a "dummy" node where pubsub#deliver_payloads is set to true. IIRC recent changes to XEP-0060 require services to return an error on unknown configuration values. But this is fragile until this requirement is deployed widely. So ultimately, the entity possibly also wants to verify if setting has been respected and became effective.

encrypted to self

In case of a <signcrypt/> element, the OpenPGP message embedded in the <openpgp/> element MUST be encrypted and signed, and SHOULD also be encrypted to self. In case of a <sign/> element, the OpenPGP message MUST be signed and MUST NOT be encrypted. In case of <crypt/> the OpenPGP message MUST NOT be signed, but MUST be encrypted.

The note "and SHOULD also be encrypted to self" is used for <signcrypt/>, but not for <crypt/>- Should is be like this?

In case of a <signcrypt/> element, the OpenPGP message embedded in the <openpgp/> element MUST be encrypted and signed, and SHOULD also be encrypted to self. In case of a <sign/> element, the OpenPGP message MUST be signed and MUST NOT be encrypted. In case of <crypt/> the OpenPGP message MUST NOT be signed, but MUST be encrypted, and SHOULD also be encrypted to self.

This page should be used to discuses the XEP's and implementation of XEP-0373: OpenPGP for XMPP. If you think there are some things which are wrong, feel free to contact me.


There are different people with different background knowledge about OpenPGP / GnuPG. XMPP OX should be able to integrate OpenPGP in clients which hides the technical details of OpenPGP to the user. But, XMPP OX should also useable for technical people which may have a OpenPGP Smartcard or a Token.

At the end of the day, the different client applications should be able to share information and messages.

OpenPGP via GnuPG

There are two use cases to create the key material.

Users with technical background may have his own key or prefer to generate his own key via GnuP. This is not a question about trust the gnupg application or trust the xmpp client application, this is more a habit of the user.

Non-technical users may prefer that the XMPP client acts on behalf of the user and will generate the key material. Even, without asking the user a lot of questions.

Generating key

Basically both use cases are fine and the best way is, to let the user decides which he would like to use. Generate a Key via gpg can be done by

gpg --full-gen-key

GnuPG <= 2.2.27 will generate a rsa3072 key by default and ask for Username and E-Mail Address during the full-gen-key setup.

The future-default of is ECC 25519. It may be better to use an ECC key instead of RSA, because it's much faster and smaller. You can use the quick-generate-key option to generate an XMPP-URI as UID

gpg --quick-generate-key xmpp:test@domain.tld future-default default 2y

pub   ed25519 2021-03-28 [SC] [verfällt: 2023-03-28]
uid                      xmpp:test@domain.tld
sub   cv25519 2021-03-28 [E]

Generating the key within the XMPP client is up to the developer. It's recommend to have such a option, to make the on boarding for non technical people easier.


There may people which prefer one key pair for E-Mail and one dedicated key pair for XMPP. There may also people ( independent of this knowledge ) which prefer to have one key pair for all "services". In the most cases, at least I know, it will be done via the OpenPGP UID.

The user should be able to manage his key pair. Also, the XMPP Client should be able to assistant, by adding a UID for the XMPP Account.

A key can look like this:

pub   rsa2048 2020-05-01 [SCEA]
uid        [ unbekannt ] xmpp:alice@domain.tld

or like this:

pub   rsa4096 2019-05-14 [SC] [verfällt: 2021-05-13]
uid        [ ultimativ ] Name <mailbox@domain.tld>
uid        [ ultimativ ] Name (FSFE) <mailbox@domain1.tld>
uid        [ ultimativ ] Name (devLUG) <mailbox@domain2.tld>
uid        [ ultimativ ] xmpp:user@domain.tld
uid        [ ultimativ ] xmpp:xmpp:alice@domain.tld
sub   rsa4096 2019-05-14 [E] [verfällt: 2021-05-13]
sub   rsa4096 2019-05-14 [A] [verfällt: 2021-05-13]
  • If there is a private key with an existing UID for the account, just use it.
  • If there is a private key, but there is no private key with a UID of the account, ask the user to add a UID
  • If there is no private key, create one for the XMPP account.
gpg --quick-add-uid <FINGERPRINT> xmpp:user@domain.tld 

Export a public key

Sharing the public key is also a question about privacy. If the user has only one key pair which is used by XMPP, only. There may not many problems to share those key via XMPP PEP. If a user have a key with more UIDs and is using the WoT, the user may prefer which information should / shouldn't included within the public key.

By default, the public will include Name, E-Mail-Addresses, XMPP Addresses of all OpenPGP UIDs in the public key. The public key also includes the signatures. If the user prefer to publish his public key with minimal information, he can do so by

gpg --export --export-options export-minimal  --export-filter 'keep-uid=uid =~ xmpp:local@domain.tld' MY_FINGERPRINT > /tmp/test.gpg

In this cases, just the UID with the xmpp-Address will be extracted and no signatures. I think it is important, that the user can decides if he creates the public key export and push int on PEP or if the XMPP Client ( in think in most cases the full export) should do it.


The user should decides which trust model the user prefers.

Users which just would like to use it and do not crate much of trust fingerprints, may should use trust-model TOFO (Trust On First Use).

Option trust-model and tofu-default-policy in .gnupg/gpg.conf. Users which prefer trust-model pgp should be able to use the WoT (default in gnupg).

I think the WoT is not nonsense. There is maybe an issues, that not all clients supporting a friendly way to sign key and publish it.

One important part of the asymmetric cryptography is the exchange of the public key and verify those key (certificate - singing of a key). With the singing of the key and building the gnupg's trust db, I think the WoT is a powerful and helpful concept to verify the keys of other persons.

The main problem I see, there is less interest and the second problem, lot of clients (not only XMPP client) don't integrate a nice UI for the users. Using the WoT requires 4 steps:

  • get the public key of the contact
  • verify the fingerprint of the public key
  • signing the public key
  • sent the signed public key encrypted back to the contact

The 2nd step is the step which has to be managed by the human. I think all other steps can be done by XMPP Clients.

Sharing the private key

This topic is not easy. I think, it should also be optional at all. In some cases it may helpful and a nice feature, and in other cases it won't work at all.

Sharing the private key is required to support multi devices.

Lot of non technical person moved to an "smartphone only mode". There are a lot of people which are using IM / Mail only on the smartphone. For those people, there is no need to share the private key. It would be included in the backup.

There are also people which are using a smartphone, Desktop and Laptop and don't won't to care about key management. For those people the sharing of private key on PEP is a very nice feature.

For people using Smartcard / Token, it don't make sense to share the key. The key is on a hardware device and they just need the public key and the token.



I tried to write the Fundamentals just as possible use cases. This don't mean that the XMPP Clients should implement all. But, we should make sure, that we are able to support the use cases as much as possible, but it shouldn't be necessary to implement all. (For example, it would be difficult to implement thinks like "--export-options export-minimal --export-filter", I won't implement it - but we should be able to work with it, when the user would like to gpg to export it)

  • Examples

If a XMPP Client has been implemented that it will check the PEP of the contact, first. The Clients OX will not work, if there is no public key. This could be a problem, if others client doesn't require the publishing of public key on PEP.

If the XMPP Client doesn't check the UIDs / Sub-Key of the Mainkey, it could be an issue if there key looking different.

History of version of public key

Requesting Public Keys

Note that the result may contain multiple pubkey elements. Only the public keys found in the most recent item MUST be used. Requesters may want to limit the results to the most recent item using the 'max_items' attribute set to '1'.

Is it required to have a versions for the public key?

A public key can be changed for

  • Adding or removing UIDs - No need to have a version, just need the current public key
  • Adding or removing (revoke) Subkeys - No need to have a version, just need the current public key
  • Change the expiration date - No need to have a version, just need the current public key
  • Adding Key signatures - No need to have a version, just need the current public key

I think there is no need to provide a history.

Other use cases which we should check?

Key-lookup / GnuPG's Keyring / Homedir

How should the Sender fetch the public key and where should it be stored?

  • The key-lookup can be done via a lookup of all known keys with the XMPP-URI as UID.
 sec   rsa3072 2020-05-01 [SC] [verfällt: 2022-05-01]
 uid        [ ultimativ ] Doctor Snuggles <doctor.snuggles@domain.tld>
 uid        [ ultimativ ] xmpp:doctor.snuggles@domain.tld
 ssb   rsa3072 2020-05-01 [E] [verfällt: 2022-05-01]

In this example there is a UID for the E-Mail and an additional UID with the XMPP-URI as Name (`gpg --quick-add-uid`). I guess, most of the time the user has just one key per account. It could be, that a user has one key for his Desktop and one key for his laptop. There is also the possibility - I didn't try yet - to create two subkeys [E] and have one key stored on the Desktop and one on the laptop.

 gpg --quick-add-key 7FA1EB8644BAC07E7F18E7C9F121E6A6F3A0C7A5 rsa3072 encr 2y
 sec   rsa3072 2020-05-01 [SC] [verfällt: 2022-05-01]
       7FA1 EB86 44BA C07E 7F18  E7C9 F121 E6A6 F3A0 C7A5
 uid        [ ultimativ ] Doctor Snuggles <doctor.snuggles@domain.tld>
 uid        [ ultimativ ] xmpp:doctor.snuggles@domain.tld
 ssb   rsa3072 2020-05-01 [E] [verfällt: 2022-05-01]
       AFBB 126C DC71 912E F5C0  F47D FC18 A7DA 7495 5B8A
 ssb   rsa3072 2020-06-02 [E] [verfällt: 2022-06-02]
       6C88 E0E5 3F69 A137 2F0F  A36A 3AED DD36 93E7 8BCE

There are two [E] subkeys.

  • We shouldn't care how the user receives the public key. This should be done via Keyserver, WKD, E-Mail or XMPP PEP.

If I read a Mail via Mailinglist and get the public key via WKD, it would also be possible to use those key for XMPP. Also, if I'm going to update the public keys. This is important for the WoT and to make sure that a key is valid, because of new signatures of the public key.

  • The user should be able to use his own key. For instance, if the user would like to use his OpenPGP Smartcard / Token for E-Mail and XMPP.
  • The user should be able to manage his public keys like all other keys GnuPG's `--update-trustdb`and `refresh-keys`
  • The user should be able to use WoT pgp or tofu or tofu+pgp mode
  • The WoT is important for messages which has been signed or signcypted

I think it will be better to use the same keyring and homedir like GnuPG is using.

XEP Review

XEP-0373: OpenPGP for XMPP

Date of a public key

In Section The OpenPGP Public-Key Data Node Example 3 is a date attribute in the pubkey tag. In Section Requesting Public Keys Example 8. is no date attribute in the response. The Text "Note that the result may contain multiple pubkey elements. Only the public keys found in the most recent item MUST be used." may reference to the date attribute.

"Requesters may want to limit the results to the most recent item using the 'max_items' attribute set to '1'." Does this constrain guarantee that the response is always the most recent item?

I think there is no need to have more than one version of a public key on the PEP. Within OpenPGP (local Keyring, Keyserver, Web Key Directory, doesn't support a version of public key AFAIK). The user should be able to update the item with his current version of the key.

XEP-0420: Stanza Content Encryption


In Section Affix Elements rpad is defined like

"Prevent known ciphertext and message length correlation attacks. The content of this element is a randomly generated sequence of random length between 0 and 200 characters. TODO: sane boundaries?"

In Example 1 is rpad



rpad: 6mWBrmp77XWx/srrjVNwS32eXf5
rpad: B1LXIxB9xPZwzD5mXr6jiIiPyr0FpworMt5GpniK8JnyRVVVnWJzYbyS6kVMEbTmxDsgmwCOV7dpczyl1SiBO1DhzKhdxHCW6gsMH1nyAOC9dHW/JJM2L/fklEge4d+ktrC0
rpad: ebeJpeWb4KLt
rpad: P7ZgMDX6b4gFN4TN0/VSl6315bgvXxnHz2+AVmSVZVzl57ztMVQ5NtRZb2yVEZA
rpad: BQCJ/1e8iY2nJTW0RdP8bhg9NOaNZr/O/xvgTYCY+t0zFpEJMBaCY9sKWKfFePtB3BLva2HQ17zw2kFVDn50Kp8n+VKhctSfwofda51NQq8Giug+A5057Ma9NSjMZt
rpad: PyOyTdHT2WiXeTuevJdS5yQLzLtxrf3g6GbN4qKrzPKLgQMGOo8cd3bayBO9o1yZHy341KoCtDMhyhwhDl/aMTXNh2bPrjIpeAJ6xDLjL6Ph/OB32GMTvMqtpy9vbygXo3


Table 1: Overview about different crypto property elements

Receiving clients MUST check, if the JID matches the to attribute of the enclosing stanza and otherwise alert the user/reject the message

This could be full JID or bare JID, depends on the Envelope Element? Should be a plain string compare?

Receiving clients MUST check whether the difference between the timestamp and the sending time derived from the stanza itself lays within a reasonable margin.


Multi-User-Chat / Group Chat

There are different ways of tackling multi user-chat.

The naive way would be to simply gather all the keys of all recipients and encrypt outgoing messages to all recipient keys.

Another possibility (experimental, not sure if there is support for this in libraries/the OpenPGP spec yet) would be to use Proxy-Reencryption using ECC/PQC keys. This would require server-side support:

  • There is a group chat key per group chat.
  • (For ECC keys) For each member of the chat, the point on the curve gets multiplied by a unique scalar. The result is a new recipient key.
  • The server distributes recipient keys to the recipients
  • When sending a message, the user uses the group chat's encryption key
  • The server "reencrypts" the message for each recipient and delivers it
  • The users can decrypt the message

This methodology prevents the server from learning about message contents, but simplifies key management. Unfortunately this would require server-side support and support in OpenPGP spec/tooling, so this is very future-work-ish.

See https://www.researchgate.net/publication/299487198_Elliptic_Curve_Based_Proxy_Re-Encryption See "Automatic Forwarding" section in https://cryptpad.fr/pad/#/2/pad/view/9IyR9CkooqMQHOiUQ2a7UE88FAMklY1XF2vqnkCY6xg/


Issues found during implementation and testing.

I'm trying to work on some xmppc, eagle, profanity to implement the use of OpenPGP in OX. For testing I'm using the OX Plugin of gajim also. This chapter I will write which "issue" I found, which should be clarified.


The first and important part is the key-lookup of the public key. I think this would be done for all clients in the same way?

  • get all public keys which are stored in the local keyring
  • check if the key is not revoked, not disabled, not expired
  • check for the key / subkey with capability [E] - not revoked, not disabled, not expired
  • check all UIDs for the key
  • look for a UID with the XMPP-URI

This key should be used to encrypted the message.


Not sure what should we do with it? Currently, I implemented that the message it encrypt for recipient and sender.