mirror of
https://github.com/moparisthebest/xeps
synced 2024-12-22 15:48:52 -05:00
788 lines
34 KiB
XML
788 lines
34 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [
|
|
<!ENTITY signcrypt "<signcrypt/>">
|
|
<!ENTITY sign "<sign/>">
|
|
<!ENTITY crypt "<crypt/>">
|
|
<!ENTITY openpgp "<openpgp/>">
|
|
<!ENTITY payload "<payload/>">
|
|
<!ENTITY rfc3156 "<span class='ref'><link url='http://tools.ietf.org/html/rfc3156'>RFC 3156</link></span> <note>RFC 3156: MIME Security with OpenPGP <<link url='http://tools.ietf.org/html/rfc3156'>http://tools.ietf.org/html/rfc3156</link>>.</note>" >
|
|
<!ENTITY rfc3629 "<span class='ref'><link url='http://tools.ietf.org/html/rfc3629'>RFC 3629</link></span> <note>RFC 3629: UTF-8, a transformation format of ISO 10646 <<link url='http://tools.ietf.org/html/rfc3629'>http://tools.ietf.org/html/rfc3629</link>>.</note>" >
|
|
<!ENTITY % ents SYSTEM 'xep.ent'>
|
|
%ents;
|
|
]>
|
|
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
|
|
<xep>
|
|
<header>
|
|
<title>OpenPGP for XMPP</title>
|
|
<abstract>Specifies end-to-end encryption and authentication of data with the help of
|
|
OpenPGP, announcement, discovery and retrieval of public keys and a
|
|
mechanism to synchronize secret keys over multiple
|
|
devices.</abstract>
|
|
<legal>
|
|
<copyright>This XMPP Extension Protocol is copyright (c) 1999 - 2016 by the XMPP Standards Foundation (XSF).</copyright>
|
|
<permissions>Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP
|
|
Standards Foundation.</permissions>
|
|
<warranty>## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. In no event shall the XMPP Standards Foundation or the authors of this Specification be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification. ##</warranty>
|
|
<liability>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising out of the use or inability to use the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.</liability>
|
|
<conformance>This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which may be found at <<link url='http://xmpp.org/extensions/ipr-policy.shtml'>http://xmpp.org/extensions/ipr-policy.shtml</link>> or obtained by writing to XSF, P.O. Box 1641, Denver, CO 80201 USA).</conformance>
|
|
</legal>
|
|
<number>0373</number>
|
|
<status>Experimental</status>
|
|
<type>Standards Track</type>
|
|
<sig>Standards</sig>
|
|
<approver>Council</approver>
|
|
<dependencies>
|
|
<spec>XMPP Core</spec>
|
|
<spec>XEP-0030</spec>
|
|
<spec>XEP-0082</spec>
|
|
<spec>XEP-0163</spec>
|
|
<spec>XEP-0223</spec>
|
|
<spec>XEP-0334</spec>
|
|
</dependencies>
|
|
<supersedes/>
|
|
<supersededby/>
|
|
<shortname>ox</shortname>
|
|
&flow;
|
|
<author>
|
|
<firstname>Dominik</firstname>
|
|
<surname>Schürmann</surname>
|
|
<email>dominik@dominikschuermann.de</email>
|
|
<jid>dominik@dominikschuermann.de</jid>
|
|
</author>
|
|
<author>
|
|
<firstname>Vincent</firstname>
|
|
<surname>Breitmoser</surname>
|
|
<email>look@my.amazin.horse</email>
|
|
<jid>valodim@stratum0.org</jid>
|
|
</author>
|
|
<revision>
|
|
<version>0.1.3</version>
|
|
<date>2016-07-15</date>
|
|
<initials>fs (XEP Editor: ssw)</initials>
|
|
<remark><p>Update acknowledgements.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.1.2</version>
|
|
<date>2016-07-11</date>
|
|
<initials>bjc (XEP Editor: ssw)</initials>
|
|
<remark><p>Minior editorial fixes.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.1.1</version>
|
|
<date>2016-06-04</date>
|
|
<initials>fs</initials>
|
|
<remark><p>Minior editorial fixes.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.1</version>
|
|
<date>2016-05-10</date>
|
|
<initials>XEP Editor (ssw)</initials>
|
|
<remark><p>Initial published version approved by the XMPP Council.</p></remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.0.1</version>
|
|
<date>2016-03-25</date>
|
|
<initials>fs</initials>
|
|
<remark><p>First draft.</p></remark>
|
|
</revision>
|
|
</header>
|
|
|
|
<section1 topic='Introduction' anchor='intro'>
|
|
|
|
<p>This XMPP extension protocol specifies the foundations of
|
|
end-to-end encryption and authentication, based on digital
|
|
signatures, of data with the help of OpenPGP. Additional XEPs will
|
|
use this extension protocol as building block when specifying their
|
|
own OpenPGP profile suiting their use case. One such profile is the
|
|
Instant Messaging Profile specified in &xep0374;.</p>
|
|
|
|
<p>XMPP provides the mechanisms to solve a lot of issues that come
|
|
with modern day OpenPGP usage. For example, based on &xep0163; this
|
|
specification describes a standardized way to discover OpenPGP
|
|
public keys of other entities. But unlike the OpenPGP keyservers,
|
|
this process establishes a strong relation between the key and the
|
|
key's owning entity (usually a human user). A similar mechanism
|
|
described herein allows to synchronize the secret key(s) across
|
|
multiple devices.</p>
|
|
|
|
<p>OpenPGP in return allows for end-to-end encrypted data to be
|
|
exchanged between one, two or even multiple entities
|
|
(multi-end-to-multi-end encryption). Therefore this XEP can be used
|
|
for example to implement end-to-end encrypted &xep0045;.</p>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Glossary' anchor='glossary'>
|
|
|
|
<dl>
|
|
<di><dt>OpenPGP element</dt><dd>An XMPP extension element: &openpgp; qualified by the 'urn:xmpp:openpgp:0' namespace</dd></di>
|
|
<di><dt>OpenPGP content element</dt><dd>An element embedded via OpenPGP in a &openpgp; element. Either one of &signcrypt;, &sign; or &crypt;, qualified by the 'urn:xmpp:openpgp:0' namespace.</dd></di>
|
|
<di><dt>PEP</dt><dd>Personal Eventing Protocol (<cite>XEP-0163</cite>)</dd></di>
|
|
<di><dt>Public key PEP node</dt><dd>A PEP node containing an entity's public OpenPGP key.</dd></di>
|
|
<di><dt>Secret key PEP node</dt><dd>A PEP node containing an entity's encrypted secret OpenPGP key.</dd></di>
|
|
</dl>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='OpenPGP Encrypted and Signed Data' anchor='signcrypt'>
|
|
|
|
<section2 topic='Exchanging OpenPGP Encrypted and Signed Data' anchor='exchange'>
|
|
|
|
<p>The &openpgp; extension element qualified by the
|
|
'urn:xmpp:openpgp:0' namespace is used in order to exchange
|
|
encrypted and signed data.</p>
|
|
|
|
<example caption='The &openpgp; extension within a message.'><![CDATA[
|
|
<message to='juliet@example.org'>
|
|
<openpgp xmlns='urn:xmpp:openpgp:0'>
|
|
BASE64_OPENPGP_MESSAGE
|
|
</openpgp>
|
|
</message>]]></example>
|
|
|
|
<p>The text content of &openpgp; ("BASE64_OPENPGP_MESSAGE") is a
|
|
Base64 encoded (&rfc4648; <link
|
|
url='https://tools.ietf.org/html/rfc4648#section-4'>§ 4</link>)
|
|
OpenPGP message as specified in &rfc4880; which contains an
|
|
encrypted and/or signed UTF-8 (&rfc3629;) encoded string. This
|
|
string MUST correspond to exactly one OpenPGP content element,
|
|
that is, it represents either a &signcrypt;, a &sign; or a &crypt;
|
|
extension element qualified by the 'urn:xmpp:openpgp:0'
|
|
namespace. Note that OpenPGP's ASCII Armor is not used, instead
|
|
the XMPP client MUST encode the raw bytes of OpenPGP message using
|
|
Base64.</p>
|
|
|
|
<p>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.</p>
|
|
|
|
<example caption='The &signcrypt; extension element.'><![CDATA[
|
|
<signcrypt xmlns='urn:xmpp:openpgp:0'>
|
|
<to jid='juliet@example.org'/>
|
|
<time stamp='2014-07-10T17:06:00+02:00'/>
|
|
<rpad>
|
|
f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv
|
|
</rpad>
|
|
<payload>
|
|
<body xmlns='jabber:client'>
|
|
This is a secret message.
|
|
</body>
|
|
</payload>
|
|
</signcrypt>]]></example>
|
|
|
|
<p>OpenPGP content elements MUST possess exactly one 'time'
|
|
element as direct child elements. The &signcrypt; and &crypt;
|
|
content elements MUST contain at least one 'to' element(s), which
|
|
MUST have a 'jid' attribute containing the intended recipient's
|
|
XMPP address of the signed and/or encrypted data to prevent
|
|
Surreptitious Forward Attacks<note>Jee Hea An, Yevgeniy Dodis, and
|
|
Tal Rabin. 2002. On the Security of Joint Signature and
|
|
Encryption. In Proceedings of the International Conference on the
|
|
Theory and Applications of Cryptographic Techniques: Advances in
|
|
Cryptology (EUROCRYPT '02), Lars R. Knudsen
|
|
(Ed.). Springer-Verlag, London, UK, UK, 83-107. <<link
|
|
url='https://www.iacr.org/archive/eurocrypt2002/23320080/adr.pdf'>https://www.iacr.org/archive/eurocrypt2002/23320080/adr.pdf</link>></note>.
|
|
The XMPP address found in the 'to' element's 'jid' attribute
|
|
SHOULD be without Resourcepart (i.e., a bare JID). A &sign; content
|
|
element may not carry a 'to' attribute. The 'time' element MUST
|
|
have a 'stamp' attribute which contains the timestamp when the
|
|
OpenPGP content element was signed and/or encrypted in the
|
|
DateTime format as specified in &xep0082; § 3.2. The &signcrypt;
|
|
and &crypt; elements SHOULD furthermore contain a 'rpad' element
|
|
which text content is a random-length random-content padding.</p>
|
|
|
|
<table caption='OpenPGP Content Element Properties'>
|
|
<tr>
|
|
<th>Content Element</th>
|
|
<th>'to' Element</th>
|
|
<th>'time' Element</th>
|
|
<th><rpad/> Element</th>
|
|
<th><payload/> Element</th>
|
|
</tr>
|
|
<tr>
|
|
<td>&signcrypt;</td>
|
|
<td>MUST have at least one</td>
|
|
<td>MUST have exactly one</td>
|
|
<td>SHOULD have exaclty one</td>
|
|
<td>MUST have exactly one</td>
|
|
</tr>
|
|
<tr>
|
|
<td>&sign;</td>
|
|
<td>MAY NOT contain one</td>
|
|
<td>MUST have exaclty one</td>
|
|
<td>NOT REQUIRED</td>
|
|
<td>MUST have exactly one</td>
|
|
</tr>
|
|
<tr>
|
|
<td>&crypt;</td>
|
|
<td>MUST have at least one</td>
|
|
<td>MUST have exaclty one</td>
|
|
<td>SHOULD have exaclty one</td>
|
|
<td>MUST have exactly one</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>OpenPGP content elements MUST possess exactly one &payload;
|
|
element. The child elements of &payload; can be seen as OpenPGP
|
|
secured Stanza extension elements which are encrypted and/or
|
|
signed. After the &openpgp; element and the including &signcrypt;,
|
|
&sign; or &crypt; element was verified, they are processed
|
|
according to the specification of the relevant OpenPGP for XMPP
|
|
profile (see for example &xep0374;).</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Verification of &openpgp; Content' anchor='openpgp-verification'>
|
|
|
|
<p>Recipients MUST verify that the signature is valid, that the
|
|
signature's key corresponds to the sender's key, and that the
|
|
sender's key has a User ID containing the sender's XMPP
|
|
address in the form "xmpp:juliet@example.org" (for details see
|
|
<link url='#openpgp-user-ids'>"OpenPGP User IDs"</link>). Thus,
|
|
the recipient may
|
|
need to retrieve the key from the Personal Eventing Protocol node
|
|
as described above. At least one of the XMPP addresses found in
|
|
the 'to' elements contained in OpenPGP content element MUST
|
|
correspond to the outer 'to' of the XMPP &MESSAGE;. Furthermore,
|
|
recipients are RECOMMENDED to verify the 'time' element for
|
|
plausibility or to display it to a user for verification.</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Announcing and Discovering the Public Key via PEP' anchor='announcing-discover-pubkey'>
|
|
|
|
<p>Parties interested in exchanging encrypted data between each
|
|
other via OpenPGP need to know the public key(s) of the
|
|
recipients. The following section specifies a mechanism to announce
|
|
and discover public keys.</p>
|
|
|
|
<section2 topic='Announcing the Public Key via PEP' anchor='annoucning-pubkey'>
|
|
|
|
<p>In order to announce the public key, the client needs to store
|
|
it in a PEP node. The public key data, as specified in <cite>RFC
|
|
4880</cite>, is stored within a <pubkey/> element which is a
|
|
child element of the <pubkeys/> element qualified by the
|
|
'urn:xmpp:openpgp:0' namespace. Note that OpenPGP's ASCII Armor is
|
|
not used, instead the XMPP client MUST encode the public key using
|
|
Base64. Client SHOULD only try to store the public key if the
|
|
Personal Eventing Protocol service supports persistent-items, thus
|
|
it SHOULD check if the service reports the
|
|
'http://jabber.org/protocol/pubsub#persistent-items' feature.</p>
|
|
|
|
<example caption='Saving the public key in the PEP node.'><![CDATA[
|
|
<iq from='juliet@example.org/balcony' type='set' id='1'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<publish node='urn:xmpp:openpgp:0'>
|
|
<item>
|
|
<pubkeys xmlns='urn:xmpp:openpgp:0'>
|
|
<pubkey>
|
|
BASE64_OPENPGP_PUBLIC_KEY
|
|
</pubkey>
|
|
</pubkeys>
|
|
</item>
|
|
</publish>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Discovering the Public Key via PEP' anchor='discover-pubkey'>
|
|
|
|
<p>In order to discover the public key of an XMPP entity, clients
|
|
send a PubSub &IQ; request to the entity's bare JID of which it
|
|
wants to know the public key.</p>
|
|
|
|
<example caption='Requesting a OpenPGP public key from an XMPP entity.'><![CDATA[
|
|
<iq from='romeo@example.org/orchard'
|
|
to='juliet@example.org'
|
|
type='get'
|
|
id='getpub'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<items node='urn:xmpp:openpgp:0'
|
|
max_items='1'/>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
<example caption='Personal Eventing Protocol result containing the requested public key.'><![CDATA[
|
|
<iq from='juliet@example.org'
|
|
to='romeo@example.org/orchard'
|
|
type='result'
|
|
id='getpub'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<items node='urn:xmpp:openpgp:0'>
|
|
<item>
|
|
<pubkeys xmlns='urn:xmpp:openpgp:0'>
|
|
<pubkey>
|
|
BASE64_OPENPGP_PUBLIC_KEY
|
|
</pubkey>
|
|
</pubkeys>
|
|
</item>
|
|
</items>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
|
|
<p>Note that the result may contain multiple pubkey elements. Only
|
|
the public keys found in the most recent MUST be used. Requesters
|
|
may want to limit the results to the most recent item using the
|
|
'max_items' attribute set to '1'. Clients could alternatively use
|
|
&xep0059; as an alternative to 'max_items' but accoding to
|
|
<cite>XEP-0060</cite> RSM is not (yet) mandatory for PubSub
|
|
services.</p>
|
|
|
|
<p>Some XMPP services may not provide the Personal Eventing
|
|
Protocol feature required to provide the mechanism described
|
|
here. If so, they will return an &IQ; error of type
|
|
service-unavailable.</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Synchronizing the Secret Key with a Private PEP Node' anchor='synchro-pep'>
|
|
|
|
<p>A private PEP node is used to allow XMPP clients to synchronize
|
|
the user's secret OpenPGP key. Where private PEP node is defined: A
|
|
PEP node in whitelist mode where only the bare JID of the key
|
|
owner is whitelisted as described in &xep0223;. The secret key is
|
|
additionally encrypted.</p>
|
|
|
|
<section2 topic='Required PEP features'>
|
|
|
|
<p>The used PEP server MUST support PEP and the whitelist access
|
|
model. It SHOULD also support persistent items.</p>
|
|
|
|
<section3 topic='Discovering support'>
|
|
|
|
<example caption='Account owner queries server regarding protocol support'><![CDATA[
|
|
<iq from='juliet@capulet.lit/balcony'
|
|
to='juliet@capulet.lit'
|
|
id='disco1'
|
|
type='get'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'/>
|
|
</iq>
|
|
]]></example>
|
|
|
|
<p>The service discovery result must contain a PEP identity
|
|
'<identity category='pubsub' type='pep'/>, and the
|
|
'http://jabber.org/protocol/pubsub#access-whitelist'
|
|
feature. Ideally it also contains the
|
|
'http://jabber.org/protocol/pubsub#persistent-items'
|
|
feature</p>
|
|
|
|
<example caption='Server communicates protocol support'><![CDATA[
|
|
<iq from='juliet@capulet.lit'
|
|
to='juliet@capulet.lit/balcony'
|
|
id='disco1'
|
|
type='result'>
|
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
|
<identity category='account' type='registered'/>
|
|
<identity category='pubsub' type='pep'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#access-presence'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#auto-create'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#auto-subscribe'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#config-node'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#create-and-configure'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#create-nodes'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#filtered-notifications'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#persistent-items'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#publish'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#retrieve-items'/>
|
|
<feature var='http://jabber.org/protocol/pubsub#subscribe'/>
|
|
...
|
|
</query>
|
|
</iq>]]></example>
|
|
|
|
</section3>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Requesting Information About the Secret Key PEP Node' anchor='req-info-secret-pep-node'>
|
|
|
|
<p>In order to synchronize the secret key over a private PEP node,
|
|
clients first need to discover and verify the node for the correct
|
|
settings.</p>
|
|
|
|
<section3 topic='Client Sends Request'>
|
|
|
|
<example caption='Requesting the user's secret key.'><![CDATA[
|
|
<iq from='romeo@example.org/orchard'
|
|
to='juliet@example.org'
|
|
type='get'
|
|
id='getsecret'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<items node='urn:xmpp:openpgp:secret-key:0'
|
|
max_items='1'/>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
|
|
</section3>
|
|
<section3 topic='PEP Service Success Response'>
|
|
|
|
<example caption='Personal Eventing Protocol result containing the requested secret key.'><![CDATA[
|
|
<iq from='juliet@example.org'
|
|
to='romeo@example.org/orchard'
|
|
type='result'
|
|
id='getsecret'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<items node='urn:xmpp:openpgp:secret-key:0'>
|
|
<item>
|
|
<secretkey xmlns='urn:xmpp:openpgp:0'>
|
|
BASE64_OPENPGP_ENCRYPTED_SECRET_KEY
|
|
</secretkey>
|
|
</item>
|
|
</items>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
|
|
</section3>
|
|
<section3 topic='PEP Node Does Not Exist Response'>
|
|
|
|
<p>If the node does not exist the service will return an &IQ;
|
|
error indicating the item-not-found error condition. The
|
|
client MUST then create it with an whitelist access model.</p>
|
|
|
|
<example caption='Node does not exist'><![CDATA[
|
|
<iq from='juliet@example.org'
|
|
to='romeo@example.org/orchard'
|
|
type='error'
|
|
id='getsecret'>
|
|
<error type='cancel'>
|
|
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
|
</error>
|
|
</iq>]]></example>
|
|
|
|
</section3>
|
|
|
|
<section3 topic='PEP Not Supported'>
|
|
|
|
<p>The service will return a service-unavailable error &IQ; if
|
|
it does not support PEP.</p>
|
|
|
|
<example caption='Node does not exist'><![CDATA[
|
|
<iq from='juliet@example.org'
|
|
to='romeo@example.org/orchard'
|
|
type='error'
|
|
id='getsecret'>
|
|
<error type='cancel'>
|
|
<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
|
</error>
|
|
</iq>]]></example>
|
|
|
|
</section3>
|
|
|
|
</section2>
|
|
<section2 topic='Creating the Secret Key PEP Node'>
|
|
|
|
<example caption='Client creates secret key PEP node'><![CDATA[
|
|
<iq type='set'
|
|
from='juliet@example.org/balcony'
|
|
id='create-node'>
|
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
|
<create node='urn:xmpp:openpgp:secret-key:0'/>
|
|
<configure>
|
|
<x xmlns='jabber:x:data' type='submit'>
|
|
<field var='FORM_TYPE' type='hidden'>
|
|
<value>http://jabber.org/protocol/pubsub#node_config</value>
|
|
</field>
|
|
<field var='pubsub#access_model'>
|
|
<value>whitelist</value>
|
|
</field>
|
|
</x>
|
|
</configure>
|
|
</pubsub>
|
|
</iq>]]></example>
|
|
<example caption='Service informs requesting entity of success'><![CDATA[
|
|
<iq type='result'
|
|
to='juliet@example.org/balcony'
|
|
id='create-node'/>]]></example>
|
|
|
|
<p>The node is now created and the only affiliated entity is the
|
|
bare JID of the user, who created the node, with an affiliation as
|
|
'owner'.</p>
|
|
|
|
<p>In order to set a new secret key, clients store the encrypted
|
|
secret key as Base64 encoded raw OpenPGP message within an
|
|
<secretkey/> element qualified by the 'urn:xmpp:openpgp:0'
|
|
namespace. These secret key backups are created as follows:</p>
|
|
|
|
<ol>
|
|
<li>All secret keys that should be included in the backup MUST
|
|
be concatenated in their transferable key format (<cite>RFC
|
|
4880</cite> <link
|
|
url='http://tools.ietf.org/html/rfc4880#section-11.1'>§
|
|
11.1</link>).
|
|
</li>
|
|
<li>A backup code is generated from secure random: The backup
|
|
code consists of 24 upper case characters from the Latin
|
|
alphabet and numbers without 'O' ("LATIN CAPITAL LETTER O")
|
|
and '0' ("DIGIT ZERO") (alphabet:
|
|
<tt>123456789ABCDEFGHIJKLMNPQRSTUVWXYZ</tt>) grouped into
|
|
4-character chunks, e.g.,
|
|
<tt>TWNK-KD5Y-MT3T-E1GS-DRDB-KVTW</tt>. The characters MUST be
|
|
generated from cryptographically secure random. For example
|
|
<link
|
|
url='https://lwn.net/Articles/606141/'><tt>getrandom(2)</tt></link>,
|
|
<link
|
|
url='https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html'><tt>SecureRandom</tt></link>
|
|
or <tt>/dev/urandom</tt>. More information about the
|
|
randomness requirements for security can be found in &rfc4086;
|
|
</li>
|
|
<li>The whole backup code including the dashes is directly
|
|
used as a string to encrypt the concatenated transferable keys
|
|
as an OpenPGP message. More precisely: It is used as the
|
|
symmetric-key for a Symmetric-Key Encrypted Session Key Packet
|
|
according to <cite>RFC 4880</cite> <link
|
|
url='http://tools.ietf.org/html/rfc4880#section-5.3'>§
|
|
5.3</link>; the symmetric-key is thus 29 characters long
|
|
including the dashes. The encryption algorithm MUST be one of
|
|
the standardized OpenPGP symmetric algorithms, e.g, AES-128.
|
|
</li>
|
|
</ol>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Business Rules' anchor='rules'>
|
|
|
|
<section2 topic='OpenPGP Packet Format Version Restriction' anchor='openpgp-packet-format-version'>
|
|
|
|
<p>Implementations of this XEP MUST generate and accept only
|
|
version 4 (or higher) OpenPGP packets. Lower version OpenPGP
|
|
packets are insecure in many aspects (see for example <cite>RFC
|
|
4880</cite> <link
|
|
url='http://tools.ietf.org/html/rfc4880#section-5.5.2'>§
|
|
5.5.2</link>.).</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Implementors Advice' anchor='implementors-advice'>
|
|
|
|
<section2 topic='Design Principles and Techniques' anchor='design-and-techniques'>
|
|
|
|
<p>OpenPGP implementations have a sad history of being not very
|
|
user-friendly which results in users either not using OpenPGP or in
|
|
users wrongly using OpenPGP. Implementors of this XEP, and
|
|
additional future XEPs based on this XEP, therefore should read
|
|
<span class='ref'><link
|
|
url='http://g10code.com/steed.html'>STEED</link></span><note>Koch,
|
|
Werner, and Marcus Brinkman "STEED — Usable End-to-End
|
|
Encryption", White Paper, g10 GmbH, 2011-10-17. <<link
|
|
url='http://g10code.com/steed.html'>http://g10code.com/steed.html</link>></note>
|
|
and <span class='ref'><link
|
|
url='https://www.cs.berkeley.edu/~tygar/papers/Why_Johnny_Cant_Encrypt/OReilly.pdf'>"Why
|
|
Johnny can't encrypt"</link></span><note>Whitten, Alma, and
|
|
J. Doug Tygar. "Why Johnny Can't Encrypt: A Usability Evaluation
|
|
of PGP 5.0." Usenix Security. Vol. 1999. 1999. <<link
|
|
url='https://www.cs.berkeley.edu/~tygar/papers/Why_Johnny_Cant_Encrypt/OReilly.pdf'>https://www.cs.berkeley.edu/~tygar/papers/Why_Johnny_Cant_Encrypt/OReilly.pdf</link>></note>. Implementors
|
|
of this XEP are encouraged to provide the concepts described in
|
|
STEED:</p>
|
|
|
|
<ul>
|
|
<li>Automatic key generation</li>
|
|
<li>Automatic key distribution</li>
|
|
<li>Opportunistic encryption</li>
|
|
<li>Trust upon first contact</li>
|
|
</ul>
|
|
|
|
<p>Furthermore implementors should design the user interface for
|
|
effective security by following the design principles and
|
|
techniques for security mentioned in "Why Johnny Can't
|
|
Encrypt".</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Stanza Size' anchor='stanza-size'>
|
|
|
|
<p>Implementors should be aware that the size OpenPGP public and
|
|
secret keys is somewhere in the range of tens of
|
|
kilobytes. Applying Base64 encoding on keys, as it is described
|
|
herein, further increases the size. The formula to determine the
|
|
Base64 encoded size is: ceil(bytes / 3) * 4. Thus the lower bound
|
|
for the maximum stanza size of 10000 bytes, as specified in <cite>RFC
|
|
6120</cite> § 13.12. 4., is usually exceeded. However all XMPP server
|
|
implementations, the authors are aware of, follow the
|
|
recommendation of the RFC and do not blindly set the maximum
|
|
stanza size to such a low value, but use a much higher
|
|
threshold. Therefore, this should hardly be an issue for
|
|
implementations. Nevertheless, it is advised to keep the size of
|
|
OpenPGP keys small by removing all signatures except the most
|
|
recent self-signature on each User ID before exporting the key
|
|
(cf. GnuPG's <tt>--export-options export-minimal</tt>).
|
|
In addition, implementors are advised to handle
|
|
<policy-violation/> error responses when trying to
|
|
transmit Base64 encoded keys.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='XMPP Address Normalization' anchor='xmpp-address-normalization'>
|
|
|
|
<!-- TODO s/6122/7622/ after https://github.com/xsf/xeps/pull/138 -->
|
|
<p>The format of XMPP addresses, sometimes called JIDs, is well
|
|
defined. Thus they need to be normalized, as defined in
|
|
&rfc7622;. When implementations are required to compare XMPP
|
|
addresses for equality, as it is the case in <link
|
|
url='#openpgp-verification'>"Verification of &openpgp;
|
|
Content"</link>, then they also have to compare the normalized
|
|
versions of the addresses.</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Rationale' anchor='rationale'>
|
|
|
|
<section2 topic='Key Handling' anchor='key-handling'>
|
|
|
|
<p>This specification intentionally does not specify if the used
|
|
OpenPGP key should be a primary key or a subkey. It is even
|
|
possible to announce multiple public keys in the Personal Eventing
|
|
Protocol node. Implementations MUST be prepared to find multiple
|
|
public keys. The authors however believe that for ease of use only
|
|
one OpenPGP key specially crafted for the XMPP use case should be
|
|
created, announced and used.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='OpenPGP Element and Content Element Design' anchor='openpgp-element-design'>
|
|
|
|
<p>The &openpgp; and OpenPGP content elements are container
|
|
elements for arbitrary signed and encrypted data and can thus act
|
|
as building blocks for encrypted data included in Message, IQ and
|
|
Presence stanzas. For example, future specifications may use them
|
|
to implement encrypted versions of &xep0047; or &xep0261;.</p>
|
|
|
|
<p>Note that signed OpenPGP messages already contain a timestamp
|
|
as per the OpenPGP specification. OpenPGP content elements
|
|
nevertheless require the 'time' element because not every OpenPGP
|
|
API may provide access to the embedded OpenPGP timestamp.</p>
|
|
|
|
<p>The 'rpad' element of the OpenPGP content elements exists to
|
|
prevent length-based side channel attacks.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Addressing the Issues and Problems of XEP-0027' anchor='solving-xep0027-issues'>
|
|
|
|
<p>This specification addresses all relevant issues of &xep0027;
|
|
(<link url='https://xmpp.org/extensions/xep-0027.html#security'>§
|
|
4</link>, <link
|
|
url='https://xmpp.org/extensions/xep-0027.html#issues'>§
|
|
5</link>). It mitigates replay attacks by including the
|
|
recipient's address and a timestamp in the OpenPGP content
|
|
element<note>Full Replay attack prevention would require a
|
|
counter based approach.</note>. It allows for both, signing and
|
|
encrypting of the element. The scope of the specification was
|
|
deliberately limited to OpenPGP.</p>
|
|
|
|
<p>Features like signed presences, which is provided by <cite>XEP-0027</cite>,
|
|
may be added later on as add-on XEP to this.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='Not using OpenPGP ASCII Armor' anchor='openpgp-ascii-armor'>
|
|
|
|
<p>We decided against OpenPGP ASCII Armor (which contains an
|
|
additional checksum) and in favor for Base64, because
|
|
encoding should be part of the network application rather than the
|
|
crypto layer. Also XMPP, needs no additional error correction of payload.
|
|
In "MIME Security with OpenPGP" (<link
|
|
url='http://tools.ietf.org/html/rfc3156'>&rfc3156;</link>), ASCII Armor
|
|
has only been chosen to be backwards compatible with legacy applications
|
|
supporting non-MIME OpenPGP emails only.</p>
|
|
|
|
</section2>
|
|
|
|
<section2 topic='OpenPGP User IDs' anchor='openpgp-user-ids'>
|
|
|
|
<p>OpenPGP User IDs normally consist of a name - email address pair, e.g.,
|
|
"Juliet <juliet@example.org>" (<link
|
|
url='http://tools.ietf.org/html/rfc4880#section-5.11'><cite>RFC 4880 § 5.11</cite></link>).
|
|
For this XEP, we require User IDs of the format "xmpp:juliet@example.org".
|
|
First, it is required to have at least one User ID indicating the use
|
|
of this OpenPGP key. When doing certification of keys (key signing),
|
|
the partner must know what User ID she actually certifies.
|
|
Second, this format uses the standardized URI from <cite>XEP-0147</cite> to indicate
|
|
that this User ID corresponds to a key that is used for XMPP.
|
|
Third, having the Real Name inside provides no additional security
|
|
or guideline if this key should be certified. The XMPP address
|
|
is the only trust anchor here.</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Security Considerations' anchor='security'>
|
|
|
|
<p>The scope of this XEP is intentionally limited, so that the
|
|
specification just defines way for XMPP entities to discover,
|
|
announce and synchronize OpenPGP keys, and how to exchange signed
|
|
and encrypted data between two or more parties. Everything else is
|
|
outside its scope. For example, how 'secure' the key material is
|
|
protected on the endpoints is up to the implementation.</p>
|
|
|
|
<p>And while this XEP specifies a mechanism how to discover and
|
|
retrieve a public key, it does not define how the trust relation to
|
|
this key should be established. Even if key discovery and retrieval
|
|
over XMPP provides a stronger coupling between the possessing entity
|
|
(the XMPP address) and the key, as compared to the OpenPGP keyservers,
|
|
how a XMPP server authenticates a remote server is a server policy,
|
|
which does vary from server to server. Implementation MUST provide a
|
|
way for the user to establish and assign trust to a public key. For
|
|
example by using a QR code shown on the recipient's device screen.</p>
|
|
|
|
<p>Besides the protocol defined herein, OpenPGP implementations are
|
|
another big attack surface. Needless to say that the security of
|
|
encrypted data exchanged using this protocol depends on the security
|
|
of the used OpenPGP implementation. It is strongly RECOMMENED to use
|
|
existing implementations instead of writing your own. OpenPGP
|
|
implementations have suffered from various vulnerabilities in the past
|
|
which opened up DoS attack vectors. For example <link
|
|
url='https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-4402'>CVE-2013-4402</link>
|
|
and <link
|
|
url='https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4617'>CVE-2014-4717</link>.</p>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='IANA Considerations' anchor='iana'>
|
|
|
|
<p>This document requires no interaction with &IANA;.</p>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
|
|
|
|
<section2 topic='Protocol Namespaces' anchor='registrar-ns'>
|
|
|
|
<p>The ®ISTRAR; includes 'urn:xmpp:openpgp:0' in its registry of protocol namespaces (see &NAMESPACES;).</p>
|
|
|
|
</section2>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='XML Schema' anchor='schema'>
|
|
|
|
<p>TODO: Add after the XEP leaves the 'experimental' state.</p>
|
|
|
|
</section1>
|
|
|
|
<section1 topic='Acknowledgements' anchor='acknowledgements'>
|
|
|
|
<p>Thanks to Emmanuel Gil Peyrot, Sergei Golovan, Marc Laporte, Georg
|
|
Lukas, Adithya Abraham Philip and Brian Cully for their feedback.</p>
|
|
|
|
<p>The first draft of this specification was worked out and written
|
|
on the wall of the 'Kymera' room in one of Google's buildings by the
|
|
authors, consisting of members of the XMPP Standards Foundation and
|
|
the OpenKeychain project, at the GSOC Mentors Summit 2015. The
|
|
authors would like to thank Google for making it possible by
|
|
bringing the right people together.</p>
|
|
|
|
</section1>
|
|
</xep>
|