-
Notifications
You must be signed in to change notification settings - Fork 125
Expand file tree
/
Copy pathxep-0373.xml
More file actions
1029 lines (872 loc) · 41 KB
/
xep-0373.xml
File metadata and controls
1029 lines (872 loc) · 41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?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 % 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>
&LEGALNOTICE;
<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.7.0</version>
<date>2021-05-04</date>
<initials>ps</initials>
<remark>
<p>Recommend PubSub access model 'open' for public key data node and metadata node.</p>
</remark>
</revision>
<revision>
<version>0.6.0</version>
<date>2020-11-22</date>
<initials>fs</initials>
<remark>
<p>Fix 'to'-attribute requirements: All content elements which are signed using OpenPGP need
that attribute to prevent Surreptitious Forward Attacks. The &crypt; element does not require
one, as the intented recipient is established by the encryption itself. The XEP had the
requirements for &sign; and &crypt; mixed up.</p>
</remark>
</revision>
<revision>
<version>0.5.0</version>
<date>2020-06-19</date>
<initials>fs</initials>
<remark>
<ul>
<li>Use RFC 4880 terminology: it is "primary key", not "master key".</li>
<li>Clarify encryption of secret key material.</li>
<li>Move the information from the 'date' attribute into the item ID.</li>
</ul>
</remark>
</revision>
<revision>
<version>0.4.0</version>
<date>2018-07-30</date>
<initials>ps</initials>
<remark>Fix node name in examples</remark>
</revision>
<revision>
<version>0.3.3</version>
<date>2018-07-30</date>
<initials>ps</initials>
<remark>Improve note about OpenGPG fingerprint; editorial fixes</remark>
</revision>
<revision>
<version>0.3.2</version>
<date>2018-07-05</date>
<initials>ps</initials>
<remark>Add example and small editorial fixes</remark>
</revision>
<revision>
<version>0.3.1</version>
<date>2018-05-21</date>
<initials>ps</initials>
<remark>Fix slightly incorrect reference to RFC 4880</remark>
</revision>
<revision>
<version>0.3.0</version>
<date>2018-04-16</date>
<initials>fs</initials>
<remark>
Split public keys into metadata and data nodes.
</remark>
</revision>
<revision>
<version>0.2.1</version>
<date>2017-11-13</date>
<initials>fs</initials>
<remark>
<ul>
<li>Recommend setting the PubSub configuration field 'send_last_published_item' to 'on_sub'.</li>
<li>Only recommend persistent PubSub nodes.</li>
</ul>
</remark>
</revision>
<revision>
<version>0.2</version>
<date>2017-09-11</date>
<initials>XEP Editor (jwi)</initials>
<remark>Defer due to lack of activity.</remark>
</revision>
<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>&xep0163;</dd></di>
<di><dt>Public-Key metadata node ("metadata node")</dt><dd>A PEP node containing metadata of the entity's public OpenPGP key.</dd></di>
<di><dt>Public-Key data node ("data node")</dt><dd>A PEP node containing an entity's public OpenPGP key.</dd></di>
<di><dt>Secret-Key node</dt><dd>A PEP node containing an entity's encrypted secret OpenPGP key.</dd></di>
<di><dt>OpenPGP v4 Fingerprint String</dt><dd>A String representing the OpenPGP v4 fingerprint
of a key. If the key consists of a primary key and subkeys, this is the fingerprint of the
primary 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 the 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 &sign;
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 &crypt; 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 exactly one</td>
<td>MUST have exactly one</td>
</tr>
<tr>
<td>&sign;</td>
<td>MUST have at least one</td>
<td>MUST have exactly one</td>
<td>OPTIONAL</td>
<td>MUST have exactly one</td>
</tr>
<tr>
<td>&crypt;</td>
<td>OPTIONAL</td>
<td>MUST have exactly one</td>
<td>SHOULD have exactly 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 Public Keys 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>
<p>Two PEP node types are invovled: A "medatata node" is used to store meta information about
OpenPGP keys used by an entity while the actual public keys are stored in "data nodes".</p>
<section2 topic='The OpenPGP Public-Key Data Node' anchor='announcing-pubkey'>
<p>The public key data, as specified in &rfc4880;, is stored in a PEP data
node. Note that OpenPGP's ASCII Armor is not used, instead the XMPP client MUST encode the
public key using Base64. The id of the node MUST be "urn:xmpp:openpgp:0:public-keys:" followed
by the fingerprint string of the OpenPGP public-key contained in the data node.</p>
<p>In absence of a use-case specific access model, it is RECOMMENDED to use the 'open' access
model for the public key data node in order to give entities without presence subscription
read access to the public key.</p>
<p>The access model can be changed efficiently by using publish-options.</p>
<p>The <em>OpenPGP v4 fingerprint string</em> is obtained as follows: First the raw bytes of the
fingerprint are computed as specified in <cite>RFC 4880 § 12.2.</cite>. Then the bytes are
encoded as a hexadecimal string using upper case characters<note>This matches the representation
used by GnuPG minus the SPACE separation.</note>.</p>
<p> The publishing entity SHOULD set the PubSub item ID to the time the item is published encoded
as DateTime format specified in &xep0082;.</p>
<p>The data node MUST contain an <pubkey/> element qualified by the 'urn:xmpp:openpgp:0'
namespace. The element MUST include a <data/> element which contains the data of the key
Base64 encoded.</p>
<example caption='Saving the public key in the data node.'><![CDATA[
<iq type='set' from='juliet@example.org/balcony' id='publish1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:openpgp:0:public-keys:1357B01865B2503C18453D208CAC2A9678548E35'>
<item id='2020-01-21T10:46:21Z'>
<pubkey xmlns='urn:xmpp:openpgp:0'>
<data>
BASE64_OPENPGP_PUBLIC_KEY
</data>
</pubkey>
</item>
</publish>
<publish-options>
<x xmlns='jabber:x:data' type='submit'>
<field var='FORM_TYPE' type='hidden'>
<value>http://jabber.org/protocol/pubsub#publish-options</value>
</field>
<field var='pubsub#access_model'>
<value>open</value>
</field>
</x>
</publish-options>
</pubsub>
</iq>]]></example>
</section2>
<section2 topic='The OpenPGP Public Key Metadata Node' anchor='announcing-pubkey-list'>
<p>To update the public keys used by an entity, the metadata node is updated. Before adding a
OpenPGP key fingerprint to the metadata node, the publisher MUST ensure that the public key is available
at the corresponding data node.</p>
<p>Just like with the public key data node, in absence of a use-case specific access model,
it is RECOMMENDED to set the access model of the metadata node to 'open', such that entities
without mutual presence subscription are still able to access the node items.</p>
<p> The ID of the metadata node is 'urn:xmpp:openpgp:0:public-keys'. It contains a
<public-keys-list/> element qualified by the 'urn:xmpp:openpgp:0' namespace containing one
or more <pubkey-metadata/> elements. Every pubkey-metadata element MUST have a
'v4-fingerprint' attribute, containing the OpenPGP v4 fingerprint string, and a 'date'
attribute, containing the time the key was published or updated in DateTime format of
&xep0082;. An OpenPGP V4 fingerprint MUST NOT occur in the list more than once.</p>
<example caption='Publishing a public key to the metadata node.'><![CDATA[
<iq type='set' from='juliet@example.org/balcony' id='publish1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:openpgp:0:public-keys'>
<item>
<public-keys-list xmlns='urn:xmpp:openpgp:0'>
<pubkey-metadata
v4-fingerprint='1357B01865B2503C18453D208CAC2A9678548E35'
date='2018-03-01T15:26:12Z'
/>
<pubkey-metadata
v4-fingerprint='67819B343B2AB70DED9320872C6464AF2A8E4C02'
date='1953-05-16T12:00:00Z'
/>
</public-keys-list>
</item>
</publish>
<publish-options>
<x xmlns='jabber:x:data' type='submit'>
<field var='FORM_TYPE' type='hidden'>
<value>http://jabber.org/protocol/pubsub#publish-options</value>
</field>
<field var='pubsub#access_model'>
<value>open</value>
</field>
</x>
</publish-options>
</pubsub>
</iq>]]></example>
</section2>
<section2 topic='Discovering Public Keys of a User' anchor='discover-pubkey-list'>
<p>In order to discover the OpenPGP public keys of a remote entity, the interested entity first
queries the remote entity's metadata note to learn about the currently annouced OpenPGP
keys.</p>
<example caption='Requesting the metadata node of a user.'><![CDATA[
<iq from='romeo@example.org/orchard'
to='juliet@example.org'
type='get'
id='getmeta'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:openpgp:0:public-keys'/>
</pubsub>
</iq>]]></example>
<example caption='Personal Eventing Protocol result containing the metadata node of the user.'><![CDATA[
<iq from='juliet@example.org'
to='romeo@example.org/orchard'
type='result'
id='getmeta'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:openpgp:0:public-keys'>
<item>
<public-keys-list xmlns='urn:xmpp:openpgp:0'>
<pubkey-metadata
v4-fingerprint='1357B01865B2503C18453D208CAC2A9678548E35'
date='2018-03-01T15:26:12Z'
/>
<pubkey-metadata
v4-fingerprint='67819B343B2AB70DED9320872C6464AF2A8E4C02'
date='1953-05-16T12:00:00Z'
/>
</public-keys-list>
</item>
</items>
</pubsub>
</iq>]]></example>
</section2>
<section2 topic='Requesting Public Keys' anchor='discover-pubkey'>
<p>OpenPGP key(s) can be retrieved by querying the data node for a specific
fingerprint.</p>
<example caption='Requesting an 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:public-keys:1357B01865B2503C18453D208CAC2A9678548E35'
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:public-keys:1357B01865B2503C18453D208CAC2A9678548E35'>
<item id='2020-01-21T10:46:21Z'>
<pubkey xmlns='urn:xmpp:openpgp:0'>
<data>
BASE64_OPENPGP_PUBLIC_KEY
</data>
</pubkey>
</item>
</items>
</pubsub>
</iq>]]></example>
<p>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'. Clients could alternatively use
&xep0059; as an alternative to 'max_items' but accoding to
&xep0060; 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>
<section2 topic='Receiving notifications about key changes' anchor='pubsub-notifications'>
<p>Entities creating PEP nodes defined herein SHOULD configure the nodes as notification-only
nodes by setting 'pubsub#deliver_payloads" configuration field to 'false'.</p>
<p>Entities which are subscribed to the metadata node or advertise the
"urn:xmpp:openpgp:0:public-keys+notify" feature via &xep0030; (see &xep0060; <link
url='https://xmpp.org/extensions/xep-0060.html#filtered-notifications'>§ 9.2</link>) receive a
notification upon a node update. Entities subscribed to PEP nodes defined herein MUST be prepared
that PubSub notifications may be without the payload and only contain the published item's ID.</p>
</section2>
</section1>
<section1 topic='Synchronizing the Secret Key with a Private PEP Node' anchor='synchro-pep'>
<!--
TODO: Also split in metadata and data node? Probably not, because it could cause stale secret
keys on the service (since it is not possible to list all PEP nodes starting with
e.g. urn:xmpp:openpgp:0:secret-keys and delete old ones. We could split later anyways.
-->
<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' anchor='synchro-pep-requirements'>
<p>The used PEP server MUST support PEP and the whitelist access
model. It SHOULD also support persistent items.</p>
<section3 topic='Discovering support' anchor='synchro-pep-discover-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' anchor='client-sends-secret-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:0:secret-key'
max_items='1'/>
</pubsub>
</iq>]]></example>
</section3>
<section3 topic='PEP Service Success Response' anchor='client-receives-secret-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:0:secret-key'>
<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' anchor='error-pep-node-inexistent'>
<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' anchor='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' anchor='create-secret-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:0:secret-key'/>
<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>
<field var='pubsub#send_last_published_item'>
<value>on_sub</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>
</section2>
<section2 topic='Encrypting the Secret Key Backup' anchor='backup-encryption'>
<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.2'>§
11.1</link>). The octet indicating string-to-key usage conventions
MUST be set to zero in the corresponding Secret-Key Packet(s)
(&rfc4880; <link url='https://tools.ietf.org/html/rfc4880#section-5.5.3'>§ 5.5.3</link>).
The secret key material will be encrypted in step 4 using a
Symmetric-Key Encrypted Session Key Packet.
</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
<tt><link
url='https://lwn.net/Articles/606141/'>getrandom(2)</link></tt>,
<tt><link
url='https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html'>SecureRandom</link></tt>
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 &rfc4880; <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>
<section2 topic='PubSub Node Configuration' anchor='pubsub-node-configuration'>
<p>The Public-Key <em>metadata</em> node and the Secret-Key node SHOULD be configured to either
never send the latest item, or to send the latest item only when a new entity subscribed. Thus
the nodes 'send_last_published_item' configuration option SHOULD be set to either 'never' or
'on_sub' (see &xep0060; <link
url='https://xmpp.org/extensions/xep-0060.html#registrar-formtypes-config'>§ 16.4.4</link>).</p>
</section2>
<section2 topic='Key Enforcement' anchor='key-enforcement'>
<p>Whenever an entity becomes aware that the metadata node has changed (e.g., by receiving a PEP
update from their own account), it SHOULD check that the list contains the key they use. If the
key has been removed, the entity SHOULD reannounce it.</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'>
<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 &xep0027;,
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" (&rfc3156;), 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>" (&rfc4880; <link
url='http://tools.ietf.org/html/rfc4880#section-5.11'>§ 5.11</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 &xep0147; 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>