1 Introduction
2 ------------
3
4 MoinMessage provides a library for creating, signing, encrypting, decrypting,
5 and verifying PGP/GPG content in Python along with mechanisms for updating
6 MoinMoin wiki instances with such content in such a way that contributors can
7 be identified from their PGP signatures and such details used to authenticate
8 their contributions. It also permits PGP/GPG content to be stored in dedicated
9 message stores when received, enabling further processing of received content
10 and other means of perusal of such content.
11
12 A MoinMessage as understood by this software consists of content that is first
13 signed and then optionally encrypted, where this latter encryption step is
14 used to limit the audience of a message to its recipient and thus to restrict
15 knowledge of the message's author to the recipient. An extra signing step may
16 be employed to authenticate the sender of the message for the recipient, thus
17 providing a way of propagating encrypted messages between parties who trust
18 each other without any decryption of the content or access to details about
19 the author of the content.
20
21 Configuring GPG for a Wiki
22 --------------------------
23
24 Initialise a homedir for GPG and configure it using filesystem ACL (access
25 control list) properties:
26
27 ./scripts/init_wiki_keyring.sh WIKI WEBUSER
28
29 Here, WIKI should be replaced by the top-level wiki instance directory, and
30 WEBUSER should be the name of the user under which the Web server operates.
31
32 Note that this script may need re-running after the homedir has been changed
33 by gpg operations as gpg likes to remove permissions from various files.
34
35 Configuring GPG: Signing Keys
36 -----------------------------
37
38 For a wiki to be able to receive content, signing keys must be made available
39 within the wiki's GPG homedir so that incoming messages can have their senders
40 verified.
41
42 Consider the need to send content to a wiki yourself. To see the keys
43 available to you in your own environment:
44
45 gpg --list-keys --with-fingerprint
46
47 The full fingerprints are used when defining a user mapping in the wiki, and
48 the --with-fingerprint option is used to show them. Otherwise, only the last
49 eight characters of the fingerprints are shown.
50
51 Export the public key used when signing messages from your own environment:
52
53 gpg --armor --output 1C1AAF83.asc --export 1C1AAF83
54
55 Import the key into the wiki's GPG homedir:
56
57 gpg --homedir WIKI/gnupg --import 1C1AAF83.asc
58
59 Signing keys can also be used in the authoring of messages within a wiki, and
60 this is discussed in "The Username-to-Signing-Key Mapping" section below.
61
62 Configuring GPG: Encryption Keys
63 --------------------------------
64
65 For the wiki to receive and decrypt encrypted data, a key for the wiki must be
66 created:
67
68 gpg --homedir WIKI/gnupg --gen-key
69
70 For the wiki environment to be able to use the key, password access must be
71 disabled. This can be done by either not specifying a password or by removing
72 it later using the --edit-key option:
73
74 gpg --homedir WIKI/gnupg --edit-key 0891463A
75 passwd
76
77 Export the wiki's key for encrypting messages sent to the wiki:
78
79 gpg --homedir WIKI/gnupg --armor --output 0891463A.asc --export 0891463A
80
81 This exported key can now be imported into your own environment:
82
83 gpg --import 0891463A.asc
84
85 This key can also be used to sign relayed messages within the wiki, and this
86 is described in more detail in "The Username-to-Signing-Key Mapping" section
87 below.
88
89 Configuring the Wiki
90 --------------------
91
92 In the wiki configuration, define the following settings:
93
94 moinmessage_gpg_homedir
95 This sets the path to the homedir initialised above.
96
97 moinmessage_gpg_users_page (optional, default is MoinMessageUserDict)
98 This provides a mapping from key fingerprints to Moin usernames.
99 See "The Fingerprint-to-Username Mapping" section for details.
100
101 moinmessage_user_actions_page (default is MoinMessageUserActionsDict)
102 This defines the content modification actions for each user on pages and
103 message stores. See "The Username-to-Actions Mapping" section for details.
104
105 moinmessage_gpg_signing_users_page (optional, default is MoinMessageSigningUserDict)
106 This provides a mapping from Moin usernames to key fingerprints.
107 See "The Username-to-Signing-Key Mapping" section for details.
108
109 moinmessage_gpg_relaying_user (optional)
110 This specifies the username of a special user who will sign relayed
111 messages. Partner wikis will need to record the details of this user in
112 their fingerprint-to-user mapping (see moinmessage_gpg_users_page) to be
113 able to receive messages from this wiki.
114
115 moinmessage_gpg_relays_page (optional, default is MoinMessageRelayDict)
116 Where message relaying is specified for a recipient, the relay name will be
117 looked up in the dictionary provided by this page. See "The Relays Mapping"
118 section for details.
119
120 moinmessage_gpg_recipients_page (optional, default is MoinMessageRecipientsDict)
121 This provides a mapping from recipients to remote URLs and key fingerprints.
122 Each user can define the named page as a subpage of their own home page.
123 If no such personal mapping exists, a common mapping exists relative to the
124 site root. See "The Recipients Mapping" section for details.
125
126 moinmessage_reject_messages_without_dates (optional, default is True)
127 This causes messages sent to a wiki using the PostMessage action to be
128 rejected if date information is missing.
129
130 moinmessage_reject_missing_global_recipients (optional, default is False)
131 This causes messages sent to a wiki using the PostMessage action to be
132 rejected if the global recipients mapping does not contain the recipient.
133 This is potentially useful as an extra measure to reject unsolicited
134 messages in addition to defining user actions and requiring messages to be
135 signed by a known identity.
136
137 moinmessage_static_files (optional, may refer to the built-in htdocs directory)
138 This explicitly defines the path to static resources used by Moin, enabling
139 such resources to be attached to messages. When set, the path must refer to
140 the htdocs directory (possibly renamed) containing the different theme
141 resource directories, together with the robots.txt and favicon.ico files.
142
143 For signature verification to function, the following needs to be added:
144
145 from MoinMoin.auth.pgp import PGPAuth
146
147 This should import an authentication handler installed when the MoinMessage
148 software is installed as an extension package.
149
150 Within the configuration class itself, the auth setting needs to be updated to
151 include PGPAuth in the list of registered handlers. For example:
152
153 auth = [MoinAuth(), PGPAuth()]
154
155 This would permit the traditional Moin authentication and add signature-based
156 authentication so that messages can be accepted by the wiki.
157
158 Fingerprints and Keys
159 ---------------------
160
161 All fingerprints mentioned in the various configuration pages must exclude
162 space characters - that is, the letters and digits must appear together in a
163 continuous block of text - and refer to keys available in the wiki homedir.
164
165 The Fingerprint-to-Username Mapping
166 -----------------------------------
167
168 The mapping from fingerprints to usernames typically defined by the
169 MoinMessageUserDict page is a WikiDict having the following general format:
170
171 fingerprint:: username
172
173 Each fingerprint corresponds to a key used by a person wanting to send
174 messages to the wiki to sign such messages.
175
176 Each username must correspond to a registered user in the wiki.
177
178 If a wiki is to perform message relaying, receiving messages from partner
179 wikis and sending them on, a user is required for this purpose. You could
180 create such a user as follows:
181
182 moin --config-dir=WIKI account create --name=RelayingUser --email=messagerelay
183
184 (You may need to run this command as the Web server user to be able to change
185 the wiki installation, as well as indicating the full path to the moin program
186 either as the program name or by setting the PATH.)
187
188 After doing this, you could define an entry for the relaying user as follows:
189
190 fingerprint:: RelayingUser
191
192 Here, "fingerprint" should be substituted for a key fingerprint used by a
193 partner wiki to sign messages that it then sends to this wiki. See the next
194 section for more information on signing keys and identities.
195
196 It may very well be the case that more than one partner wiki will be sending
197 messages to this wiki: the signing key fingerprint of each partner wiki can be
198 added to this mapping and specify the same relaying user; there is no
199 restriction on each fingerprint needing to map to a different user.
200
201 The Relaying User and Incoming Messages
202 ---------------------------------------
203
204 The relaying user may also be configured to accept incoming messages for
205 routing to remote recipients.
206
207 Firstly, a home page must be defined for the relaying user, and a suitable
208 template is provided in the resource_pages directory as the RelayingUser file.
209
210 Secondly, a user actions definition for the user should be added to the user
211 actions mapping (described below), allowing the relaying user to write to the
212 message store associated with the user's home page. For example:
213
214 RelayingUser:: store:RelayingUser
215
216 Upon receiving an incoming message directed towards a known remote recipient,
217 the message will be placed in the message store for the relaying user, and
218 this store will then act as a queue for the dispatch of these messages to
219 remote sites.
220
221 The Username-to-Actions Mapping
222 -------------------------------
223
224 Each user may have a set of permitted actions defined for them so that they
225 may perform these actions by sending an incoming message to the wiki. This
226 mapping is typically defined by the MoinMessageUserActionsDict page as a
227 WikiDict having the following general format:
228
229 username:: permitted-action ...
230
231 To add content to a page, an entry of the following form would be used:
232
233 username:: Update:SomePage
234
235 Similarly, to allow an incoming message to replace a page's content, the
236 following would be used:
237
238 username:: Replace:SomePage
239
240 And to be able to add messages to a page's message store, the following would
241 be used:
242
243 username:: Store:SomePage
244
245 Multiple actions can be given in a space-separated list, with shell-like
246 quoting used for names containing spaces (and quote characters). For example:
247
248 username:: Store:"Some user's special page"
249
250 Without an entry in this mapping, messages may not perform content
251 modification or storage actions in the wiki to a given resource on behalf of
252 a given user.
253
254 Note that the action names can be case-insensitive.
255
256 The Username-to-Signing-Key Mapping
257 -----------------------------------
258
259 The mapping from usernames to fingerprints typically defined by the
260 MoinMessageSigningUserDict page is a WikiDict having the following general
261 format:
262
263 username:: fingerprint
264
265 Each fingerprint corresponds to a key available in the wiki's GPG homedir
266 generated for the purpose of signing the specified user's messages. Such a key
267 is not the same as one used by a person to send messages to the wiki since
268 only the public key is available to the wiki when verifying such messages,
269 whereas the signing of messages requires access to a private key. Thus, the
270 signing process employs a special private key known to the wiki for a user.
271
272 To create such a key, the following command can be used:
273
274 gpg --homedir WIKI/gnupg --gen-key
275
276 This is just like creating a key for the wiki itself (see "Configuring GPG for
277 a Wiki" above), but you will label the key appropriately for the user and
278 associate the key with the user in the mapping described above. Remember to
279 remove the passphrase so that the wiki can access the key.
280
281 If a wiki is to perform message relaying, the special relaying user must be
282 defined in this mapping together with an appropriate key fingerprint. You can
283 use the key generated during the wiki's configuration (see "Configuring GPG
284 for a Wiki" above) for this purpose. This fingerprint can then be used by
285 partner wikis in their fingerprint-to-user mapping in order to verify incoming
286 messages and to process them as relayed messages.
287
288 All signing keys must be made available in their public form to partner and
289 recipient wikis so that they are able to verify signed content. This can be
290 done as follows:
291
292 gpg --homedir=WIKI/gnupg --armor --output 3FDDF29E.asc --export 3FDDF29E
293
294 They are imported into partner and recipient wikis as follows:
295
296 gpg --homedir=WIKI/gnupg --import 3FDDF29E.asc
297
298 The Recipients Mapping
299 ----------------------
300
301 The mapping from recipients to remote URLs and fingerprints typically defined
302 by the MoinMessageRecipientsDict page is a WikiDict having the following
303 general format:
304
305 recipient:: type location [ fingerprint ]
306
307 Where the type is "page", the accompanying location must be a page name
308 indicating a page that provides a message store that will accept messages.
309 The affected page resides on the same wiki and is thus a bare page name, not
310 the URL of a page on the same or another wiki.
311
312 Where the type is "url", the accompanying location must be a URL that must
313 itself refer to a resource that can accept MoinMessage content.
314
315 Where the type is "relay", the accompanying location is an identifier that
316 must be defined in the relays mapping (see below) and yield a URL that can
317 accept MoinMessage content.
318
319 Where the type is "none" or omitted completely, the recipient is any user that
320 is allowed to fetch messages from the wiki.
321
322 Where a type of "url", "relay" or "none" has been given (or if the type is
323 omitted), a fingerprint must accompany this information in order to encrypt
324 messages sent to the specified resource.
325
326 Each fingerprint corresponds to a key used by the wiki to encrypt messages and
327 by the remote site (as identified by the URL) to decrypt messages.
328
329 Each wiki user can have their own recipients mapping by making a page, called
330 MoinMessageRecipientsDict unless overridden by the configuration, as a subpage
331 of their own home page.
332
333 The Recipients Mapping and Incoming Messages
334 --------------------------------------------
335
336 The recipients mapping can also be used to route incoming messages, and if the
337 moinmessage_reject_missing_global_recipients setting is enabled, any message
338 recipient specified in the "To" header of a message that is not present in the
339 recipients mapping will cause the message to be rejected.
340
341 The Relays Mapping
342 ------------------
343
344 The mapping from relay identifiers to remote URLs defined by the
345 MoinMessageRelayDict page is a WikiDict having the following general format:
346
347 relay:: url
348
349 The URL must be able to accept MoinMessage content, and it will typically be
350 configured so that the user or entity accepting relayed content on the remote
351 site can store such content for later propagation or retrieval.
352
353 Quick Start: Signing, Encrypting and Sending Messages
354 -----------------------------------------------------
355
356 To send a message signed and encrypted to a resource on localhost:
357
358 python tests/test_send.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
359 collection update 'An update to the wiki.' 'Another update.'
360
361 Here, the first identifier is a reference to the signing key (over which you
362 have complete control), and the second identifier is a reference to the
363 encryption key (which is a public key published for the wiki).
364
365 This needs password protection to be removed from the secret key in the Web
366 server environment. It also uses a modified trust model when invoking gpg in
367 order to avoid complaints about the identity of the sender during encryption.
368
369 To sign the encrypted message for forwarding, the above command is modified:
370
371 python tests/test_send.py 1C1AAF83 0891463A --forward 1C1AAF83 \
372 http://localhost/wiki/ShareTest \
373 collection update 'An update to the wiki.' 'Another update.'
374
375 Explicit recipient information can be provided for routing purposes:
376
377 python tests/test_send.py 1C1AAF83 0891463A --to PaulBoddie \
378 --forward 1C1AAF83 \
379 http://localhost/wiki/ShareTest \
380 collection update 'An update to the wiki.' 'Another update.'
381
382 Below, the mechanisms employed are illustrated through the use of the other
383 test programs.
384
385 Signing
386 -------
387
388 Prepare a message signed with a "detached signature" (note that this does not
389 seem to be what gpg calls a detached signature with the --detach-sig option):
390
391 python tests/test_message.py collection update 'An update to the wiki.' \
392 'Another update.' \
393 | python tests/test_sign.py 1C1AAF83
394
395 The complicated recipe based on the individual operations is as follows:
396
397 python tests/test_message.py collection update 'An update to the wiki.' \
398 'Another update.' \
399 > test.txt \
400 && cat test.txt \
401 | gpg --armor -u 1C1AAF83 --detach-sig \
402 | python tests/test_sign_wrap.py test.txt
403
404 Encryption
405 ----------
406
407 Prepare a message with an encrypted payload using the above key:
408
409 python tests/test_message.py collection update 'An update to the wiki.' \
410 'Another update.' \
411 | python tests/test_encrypt.py 0891463A
412
413 The complicated recipe based on the individual operations is as follows:
414
415 python tests/test_message.py collection update 'An update to the wiki.' \
416 'Another update.' \
417 > test.txt \
418 && cat test.txt \
419 | gpg --armor -r 0891463A --encrypt --trust-model always \
420 | python tests/test_encrypt_wrap.py
421
422 Note that "--trust-model always" is used only to avoid prompting issues.
423
424 Signing and Encrypting
425 ----------------------
426
427 Sign and encrypt a message:
428
429 python tests/test_message.py collection update 'An update to the wiki.' \
430 'Another update.' \
431 | python tests/test_sign.py 1C1AAF83 \
432 | python tests/test_encrypt.py 0891463A
433
434 The complicated recipe based on the individual operations is as follows:
435
436 python tests/test_message.py collection update 'An update to the wiki.' \
437 'Another update.' \
438 > test.txt \
439 && cat test.txt \
440 | gpg --armor -u 1C1AAF83 --detach-sig \
441 | python tests/test_sign_wrap.py test.txt \
442 | gpg --armor -r 0891463A --encrypt --trust-model always \
443 | python tests/test_encrypt_wrap.py
444
445 Signing and Encrypting then Signing
446 -----------------------------------
447
448 Where a message is to be forwarded and not decrypted, it will be signed by the
449 author, encrypted, but then signed by the forwarder (perhaps initially the
450 author):
451
452 python tests/test_message.py collection update 'An update to the wiki.' \
453 'Another update.' \
454 | python tests/test_sign.py 1C1AAF83 \
455 | python tests/test_encrypt.py 0891463A \
456 | python tests/test_sign.py 1C1AAF83
457
458 The complicated recipe based on the individual operations is as follows:
459
460 python tests/test_message.py collection update 'An update to the wiki.' \
461 'Another update.' \
462 > test.txt \
463 && cat test.txt \
464 | gpg --armor -u 1C1AAF83 --detach-sig \
465 | python tests/test_sign_wrap.py test.txt \
466 | gpg --armor -r 0891463A --encrypt --trust-model always \
467 | python tests/test_encrypt_wrap.py \
468 > test2.txt \
469 && cat test2.txt \
470 | gpg --armor -u 1C1AAF83 --detach-sig \
471 | python tests/test_sign_wrap.py test2.txt
472
473 Posting a Message
474 -----------------
475
476 To post a signed and/or encrypted message, output from the above activities
477 can be piped into the following command:
478
479 python tests/test_post.py http://localhost/wiki/ShareTest
480
481 Here, the resource "/wiki/ShareTest" on localhost is presented with the
482 message.
483
484 Fetching Messages
485 -----------------
486
487 To fetch messages from a message store associated with a page, the following
488 command can be used:
489
490 python tests/test_fetch.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
491 RETR
492
493 This should retrieve all messages from the store associated with the
494 "/wiki/ShareTest" resource on localhost.
495
496 Exporting and Sending Keys
497 --------------------------
498
499 To export a public key, the following command can be used:
500
501 python tests/text_export.py 1C1AAF83
502
503 This will output a public key block in a MIME message part suitable for
504 incorporation into a larger message or signing. Signing a message containing
505 such a key can be done as follows:
506
507 python tests/text_export.py 1C1AAF83 \
508 | python tests/test_sign.py 1C1AAF83
509
510 Obviously, this does not provide any additional reassurance about the nature
511 of the exported key other than the originator was able to sign it with the
512 same keypair information.
513
514 An alternative can involve bundling a secret with an exported key:
515
516 To export a public key, the following command can be used:
517
518 python tests/text_export.py 1C1AAF83 --secret
519
520 This does nothing more than put a key in one message part and a secret entered
521 on standard input in another part. However, the combination can then be
522 encrypted and sent in a form where the secret is clearly associated with the
523 key and can thus vouch for its authenticity:
524
525 python tests/text_export.py 1C1AAF83 --secret \
526 | python tests/test_encrypt.py 0891463A
527
528 Here, only the recipient with key 0891463A can read the specified secret,
529 check it with their copy of the secret, and thus come to a conclusion about
530 the validity of the key provided.
531
532 The Message Format
533 ------------------
534
535 Messages are MIME-encoded and consist of one or more update fragments. Where
536 the "Update-Type" header is present and set to a value of "collection", a
537 multipart message describes as many updates as there are parts. Otherwise,
538 only a single update is described by the message.
539
540 For each update, the "Update-Action" header indicates the action to be taken
541 with the update content. Where it is absent, the content is inserted into the
542 wiki page specified in the request; where it is present and set to "replace",
543 the content replaces all content on the wiki page; where it is set to "store",
544 the content is stored in a message store associated with the wiki page.
545
546 Each update may describe multiple representations of some content by employing
547 a multipart/alternative section containing parts for each of the
548 representations. Alternatively, a single message part may describe a single
549 representation.
550
551 The Message Fetching Request and Response Formats
552 -------------------------------------------------
553
554 Requests made to fetch or manipulate messages via the FetchMessages action or
555 equivalent service should have the text/x-moinmessage-fetch content type and
556 contain a newline separated sequence of commands resembling those described in
557 the POP3 specification (RFC 1939). However, the actual commands supported are
558 as follows:
559
560 STAT return the number of accessible messages
561
562 RETR [ <number to retrieve> ] retrieve the given number of messages
563 (starting from the first message in the store)
564 or all messages if the number is omitted
565
566 DELE [ <number to delete> ] delete the given number of messages (starting
567 from the first message in the store) or all
568 messages if the number is omitted
569
570 Additional commands may be implemented in future. Note that the transactional
571 commands in POP3 are not supported since the protocol is not intended to be
572 used interactively and there is no notion of a session that is preserved over
573 many requests.
574
575 Requests should be signed and encrypted in order to preserve the privacy of
576 the requester and the nature of their request.
577
578 Responses to such requests should have the text/x-moinmessage-fetch-response
579 content type and contain a complete message in the response body that should
580 be the result of signing and encrypting a response message. (The inclusion of
581 an entire message in the body is intended to work around HTTP limitations,
582 even though HTTP should really be - or have been - MIME compatible.)
583
584 The response message (before signing and encryption) is a multipart/mixed
585 message constructed similarly to collections of message updates. Each part of
586 this multipart message contains either a command result or a retrieved
587 message.
588
589 Command results should have the text/x-moinmessage-fetch-result content type
590 providing the following headers:
591
592 Request-Type the command that was provided
593 Request-Status the status of the command (OK or ERR)
594
595 Any specific result value may be provided as the payload of the command result
596 message part.
597
598 Retrieved messages should have the multipart/mixed content type and provide a
599 retrieved message in each part, where such messages may themselves be signed
600 or encrypted message representations.
601
602 HTTP Methods
603 ------------
604
605 Since MoinMoin seems to reserve POST methods for request/entity bodies that
606 contain HTML form data, it is necessary to use alternative methods to post
607 messages to a site served by MoinMoin and to fetch messages from such a site.
608 Consequently, MoinMessage uses PUT to post and fetch messages. Unfortunately,
609 MoinMoin 1.9 prevents the use of GET with request/entity bodies, and so the
610 natural usage of GET to fetch messages cannot be employed.
611
612 Contact, Copyright and Licence Information
613 ------------------------------------------
614
615 See the following Web page for more information about this work:
616
617 http://moinmo.in/ActionMarket/MoinMessage
618
619 The author can be contacted at the following e-mail address:
620
621 paul@boddie.org.uk
622
623 Copyright and licence information can be found in the docs directory - see
624 docs/COPYING.txt and docs/LICENCE.txt for more information.
625
626 Dependencies
627 ------------
628
629 MoinMessage has the following basic dependencies:
630
631 Packages Release Information
632 -------- -------------------
633
634 MoinSupport Tested with 0.5
635 Source: http://hgweb.boddie.org.uk/MoinSupport