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_static_files (optional, may refer to the built-in htdocs directory)
131 This explicitly defines the path to static resources used by Moin, enabling
132 such resources to be attached to messages. When set, the path must refer to
133 the htdocs directory (possibly renamed) containing the different theme
134 resource directories, together with the robots.txt and favicon.ico files.
135
136 For signature verification to function, the following needs to be added:
137
138 from MoinMoin.auth.pgp import PGPAuth
139
140 This should import an authentication handler installed when the MoinMessage
141 software is installed as an extension package.
142
143 Within the configuration class itself, the auth setting needs to be updated to
144 include PGPAuth in the list of registered handlers. For example:
145
146 auth = [MoinAuth(), PGPAuth()]
147
148 This would permit the traditional Moin authentication and add signature-based
149 authentication so that messages can be accepted by the wiki.
150
151 Fingerprints and Keys
152 ---------------------
153
154 All fingerprints mentioned in the various configuration pages must exclude
155 space characters - that is, the letters and digits must appear together in a
156 continuous block of text - and refer to keys available in the wiki homedir.
157
158 The Fingerprint-to-Username Mapping
159 -----------------------------------
160
161 The mapping from fingerprints to usernames typically defined by the
162 MoinMessageUserDict page is a WikiDict having the following general format:
163
164 fingerprint:: username
165
166 Each fingerprint corresponds to a key used by a person wanting to send
167 messages to the wiki to sign such messages.
168
169 Each username must correspond to a registered user in the wiki.
170
171 If a wiki is to perform message relaying, receiving messages from partner
172 wikis and sending them on, a user is required for this purpose. You could
173 create such a user as follows:
174
175 moin --config-dir=WIKI account create --name=RelayingUser --email=messagerelay
176
177 (You may need to run this command as the Web server user to be able to change
178 the wiki installation, as well as indicating the full path to the moin program
179 either as the program name or by setting the PATH.)
180
181 After doing this, you could define an entry for the relaying user as follows:
182
183 fingerprint:: RelayingUser
184
185 Here, "fingerprint" should be substituted for a key fingerprint used by a
186 partner wiki to sign messages that it then sends to this wiki. See the next
187 section for more information on signing keys and identities.
188
189 It may very well be the case that more than one partner wiki will be sending
190 messages to this wiki: the signing key fingerprint of each partner wiki can be
191 added to this mapping and specify the same relaying user; there is no
192 restriction on each fingerprint needing to map to a different user.
193
194 The Username-to-Actions Mapping
195 -------------------------------
196
197 Each user may have a set of permitted actions defined for them so that they
198 may perform these actions by sending an incoming message to the wiki. This
199 mapping is typically defined by the MoinMessageUserActionsDict page as a
200 WikiDict having the following general format:
201
202 username:: permitted-action ...
203
204 To add content to a page, an entry of the following form would be used:
205
206 username:: Update:SomePage
207
208 Similarly, to allow an incoming message to replace a page's content, the
209 following would be used:
210
211 username:: Replace:SomePage
212
213 And to be able to add messages to a page's message store, the following would
214 be used:
215
216 username:: Store:SomePage
217
218 Multiple actions can be given in a space-separated list, with shell-like
219 quoting used for names containing spaces (and quote characters). For example:
220
221 username:: Store:"Some user's special page"
222
223 Without an entry in this mapping, messages may not perform content
224 modification or storage actions in the wiki to a given resource on behalf of
225 a given user.
226
227 Note that the action names can be case-insensitive.
228
229 The Username-to-Signing-Key Mapping
230 -----------------------------------
231
232 The mapping from usernames to fingerprints typically defined by the
233 MoinMessageSigningUserDict page is a WikiDict having the following general
234 format:
235
236 username:: fingerprint
237
238 Each fingerprint corresponds to a key available in the wiki's GPG homedir
239 generated for the purpose of signing the specified user's messages. Such a key
240 is not the same as one used by a person to send messages to the wiki since
241 only the public key is available to the wiki when verifying such messages,
242 whereas the signing of messages requires access to a private key. Thus, the
243 signing process employs a special private key known to the wiki for a user.
244
245 To create such a key, the following command can be used:
246
247 gpg --homedir WIKI/gnupg --gen-key
248
249 This is just like creating a key for the wiki itself (see "Configuring GPG for
250 a Wiki" above), but you will label the key appropriately for the user and
251 associate the key with the user in the mapping described above. Remember to
252 remove the passphrase so that the wiki can access the key.
253
254 If a wiki is to perform message relaying, the special relaying user must be
255 defined in this mapping together with an appropriate key fingerprint. You can
256 use the key generated during the wiki's configuration (see "Configuring GPG
257 for a Wiki" above) for this purpose. This fingerprint can then be used by
258 partner wikis in their fingerprint-to-user mapping in order to verify incoming
259 messages and to process them as relayed messages.
260
261 All signing keys must be made available in their public form to partner and
262 recipient wikis so that they are able to verify signed content. This can be
263 done as follows:
264
265 gpg --homedir=WIKI/gnupg --armor --output 3FDDF29E.asc --export 3FDDF29E
266
267 They are imported into partner and recipient wikis as follows:
268
269 gpg --homedir=WIKI/gnupg --import 3FDDF29E.asc
270
271 The Recipients Mapping
272 ----------------------
273
274 The mapping from recipients to remote URLs and fingerprints typically defined
275 by the MoinMessageRecipientsDict page is a WikiDict having the following
276 general format:
277
278 recipient:: type location [ fingerprint ]
279
280 Where the type is "page", the accompanying location must be a page name
281 indicating a page that provides a message store that will accept messages.
282 The affected page resides on the same wiki and is thus a bare page name, not
283 the URL of a page on the same or another wiki.
284
285 Where the type is "url", the accompanying location must be a URL that must
286 itself refer to a resource that can accept MoinMessage content.
287
288 Where the type is "relay", the accompanying location is an identifier that
289 must be defined in the relays mapping (see below) and yield a URL that can
290 accept MoinMessage content.
291
292 Where the type is "none" or omitted completely, the recipient is any user that
293 is allowed to fetch messages from the wiki.
294
295 Where a type of "url", "relay" or "none" has been given (or if the type is
296 omitted), a fingerprint must accompany this information in order to encrypt
297 messages sent to the specified resource.
298
299 Each fingerprint corresponds to a key used by the wiki to encrypt messages and
300 by the remote site (as identified by the URL) to decrypt messages.
301
302 Each wiki user can have their own recipients mapping by making a page, called
303 MoinMessageRecipientsDict unless overridden by the configuration, as a subpage
304 of their own home page.
305
306 The Relays Mapping
307 ------------------
308
309 The mapping from relay identifiers to remote URLs defined by the
310 MoinMessageRelayDict page is a WikiDict having the following general format:
311
312 relay:: url
313
314 The URL must be able to accept MoinMessage content, and it will typically be
315 configured so that the user or entity accepting relayed content on the remote
316 site can store such content for later propagation or retrieval.
317
318 Quick Start: Signing, Encrypting and Sending Messages
319 -----------------------------------------------------
320
321 To send a message signed and encrypted to a resource on localhost:
322
323 python tests/test_send.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
324 collection update 'An update to the wiki.' 'Another update.'
325
326 Here, the first identifier is a reference to the signing key (over which you
327 have complete control), and the second identifier is a reference to the
328 encryption key (which is a public key published for the wiki).
329
330 This needs password protection to be removed from the secret key in the Web
331 server environment. It also uses a modified trust model when invoking gpg in
332 order to avoid complaints about the identity of the sender during encryption.
333
334 To sign the encrypted message for forwarding, the above command is modified:
335
336 python tests/test_send.py 1C1AAF83 0891463A --forward 1C1AAF83 \
337 http://localhost/wiki/ShareTest \
338 collection update 'An update to the wiki.' 'Another update.'
339
340 Explicit recipient information can be provided for routing purposes:
341
342 python tests/test_send.py 1C1AAF83 0891463A --to PaulBoddie \
343 --forward 1C1AAF83 \
344 http://localhost/wiki/ShareTest \
345 collection update 'An update to the wiki.' 'Another update.'
346
347 Below, the mechanisms employed are illustrated through the use of the other
348 test programs.
349
350 Signing
351 -------
352
353 Prepare a message signed with a "detached signature" (note that this does not
354 seem to be what gpg calls a detached signature with the --detach-sig option):
355
356 python tests/test_message.py collection update 'An update to the wiki.' \
357 'Another update.' \
358 | python tests/test_sign.py 1C1AAF83
359
360 The complicated recipe based on the individual operations is as follows:
361
362 python tests/test_message.py collection update 'An update to the wiki.' \
363 'Another update.' \
364 > test.txt \
365 && cat test.txt \
366 | gpg --armor -u 1C1AAF83 --detach-sig \
367 | python tests/test_sign_wrap.py test.txt
368
369 Encryption
370 ----------
371
372 Prepare a message with an encrypted payload using the above key:
373
374 python tests/test_message.py collection update 'An update to the wiki.' \
375 'Another update.' \
376 | python tests/test_encrypt.py 0891463A
377
378 The complicated recipe based on the individual operations is as follows:
379
380 python tests/test_message.py collection update 'An update to the wiki.' \
381 'Another update.' \
382 > test.txt \
383 && cat test.txt \
384 | gpg --armor -r 0891463A --encrypt --trust-model always \
385 | python tests/test_encrypt_wrap.py
386
387 Note that "--trust-model always" is used only to avoid prompting issues.
388
389 Signing and Encrypting
390 ----------------------
391
392 Sign and encrypt a message:
393
394 python tests/test_message.py collection update 'An update to the wiki.' \
395 'Another update.' \
396 | python tests/test_sign.py 1C1AAF83 \
397 | python tests/test_encrypt.py 0891463A
398
399 The complicated recipe based on the individual operations is as follows:
400
401 python tests/test_message.py collection update 'An update to the wiki.' \
402 'Another update.' \
403 > test.txt \
404 && cat test.txt \
405 | gpg --armor -u 1C1AAF83 --detach-sig \
406 | python tests/test_sign_wrap.py test.txt \
407 | gpg --armor -r 0891463A --encrypt --trust-model always \
408 | python tests/test_encrypt_wrap.py
409
410 Signing and Encrypting then Signing
411 -----------------------------------
412
413 Where a message is to be forwarded and not decrypted, it will be signed by the
414 author, encrypted, but then signed by the forwarder (perhaps initially the
415 author):
416
417 python tests/test_message.py collection update 'An update to the wiki.' \
418 'Another update.' \
419 | python tests/test_sign.py 1C1AAF83 \
420 | python tests/test_encrypt.py 0891463A \
421 | python tests/test_sign.py 1C1AAF83
422
423 The complicated recipe based on the individual operations is as follows:
424
425 python tests/test_message.py collection update 'An update to the wiki.' \
426 'Another update.' \
427 > test.txt \
428 && cat test.txt \
429 | gpg --armor -u 1C1AAF83 --detach-sig \
430 | python tests/test_sign_wrap.py test.txt \
431 | gpg --armor -r 0891463A --encrypt --trust-model always \
432 | python tests/test_encrypt_wrap.py \
433 > test2.txt \
434 && cat test2.txt \
435 | gpg --armor -u 1C1AAF83 --detach-sig \
436 | python tests/test_sign_wrap.py test2.txt
437
438 Posting a Message
439 -----------------
440
441 To post a signed and/or encrypted message, output from the above activities
442 can be piped into the following command:
443
444 python tests/test_post.py http://localhost/wiki/ShareTest
445
446 Here, the resource "/wiki/ShareTest" on localhost is presented with the
447 message.
448
449 Fetching Messages
450 -----------------
451
452 To fetch messages from a message store associated with a page, the following
453 command can be used:
454
455 python tests/test_fetch.py 1C1AAF83 0891463A http://localhost/wiki/ShareTest \
456 RETR
457
458 This should retrieve all messages from the store associated with the
459 "/wiki/ShareTest" resource on localhost.
460
461 Exporting and Sending Keys
462 --------------------------
463
464 To export a public key, the following command can be used:
465
466 python tests/text_export.py 1C1AAF83
467
468 This will output a public key block in a MIME message part suitable for
469 incorporation into a larger message or signing. Signing a message containing
470 such a key can be done as follows:
471
472 python tests/text_export.py 1C1AAF83 \
473 | python tests/test_sign.py 1C1AAF83
474
475 Obviously, this does not provide any additional reassurance about the nature
476 of the exported key other than the originator was able to sign it with the
477 same keypair information.
478
479 The Message Format
480 ------------------
481
482 Messages are MIME-encoded and consist of one or more update fragments. Where
483 the "Update-Type" header is present and set to a value of "collection", a
484 multipart message describes as many updates as there are parts. Otherwise,
485 only a single update is described by the message.
486
487 For each update, the "Update-Action" header indicates the action to be taken
488 with the update content. Where it is absent, the content is inserted into the
489 wiki page specified in the request; where it is present and set to "replace",
490 the content replaces all content on the wiki page; where it is set to "store",
491 the content is stored in a message store associated with the wiki page.
492
493 Each update may describe multiple representations of some content by employing
494 a multipart/alternative section containing parts for each of the
495 representations. Alternatively, a single message part may describe a single
496 representation.
497
498 The Message Fetching Request and Response Formats
499 -------------------------------------------------
500
501 Requests made to fetch or manipulate messages via the FetchMessages action or
502 equivalent service should have the text/x-moinmessage-fetch content type and
503 contain a newline separated sequence of commands resembling those described in
504 the POP3 specification (RFC 1939). However, the actual commands supported are
505 as follows:
506
507 STAT return the number of accessible messages
508
509 RETR [ <number to retrieve> ] retrieve the given number of messages
510 (starting from the first message in the store)
511 or all messages if the number is omitted
512
513 DELE [ <number to delete> ] delete the given number of messages (starting
514 from the first message in the store) or all
515 messages if the number is omitted
516
517 Additional commands may be implemented in future. Note that the transactional
518 commands in POP3 are not supported since the protocol is not intended to be
519 used interactively and there is no notion of a session that is preserved over
520 many requests.
521
522 Requests should be signed and encrypted in order to preserve the privacy of
523 the requester and the nature of their request.
524
525 Responses to such requests should have the text/x-moinmessage-fetch-response
526 content type and contain a complete message in the response body that should
527 be the result of signing and encrypting a response message. (The inclusion of
528 an entire message in the body is intended to work around HTTP limitations,
529 even though HTTP should really be - or have been - MIME compatible.)
530
531 The response message (before signing and encryption) is a multipart/mixed
532 message constructed similarly to collections of message updates. Each part of
533 this multipart message contains either a command result or a retrieved
534 message.
535
536 Command results should have the text/x-moinmessage-fetch-result content type
537 providing the following headers:
538
539 Request-Type the command that was provided
540 Request-Status the status of the command (OK or ERR)
541
542 Any specific result value may be provided as the payload of the command result
543 message part.
544
545 Retrieved messages should have the multipart/mixed content type and provide a
546 retrieved message in each part, where such messages may themselves be signed
547 or encrypted message representations.
548
549 HTTP Methods
550 ------------
551
552 Since MoinMoin seems to reserve POST methods for request/entity bodies that
553 contain HTML form data, it is necessary to use alternative methods to post
554 messages to a site served by MoinMoin and to fetch messages from such a site.
555 Consequently, MoinMessage uses PUT to post and fetch messages. Unfortunately,
556 MoinMoin 1.9 prevents the use of GET with request/entity bodies, and so the
557 natural usage of GET to fetch messages cannot be employed.
558
559 Contact, Copyright and Licence Information
560 ------------------------------------------
561
562 See the following Web page for more information about this work:
563
564 http://moinmo.in/ActionMarket/MoinMessage
565
566 The author can be contacted at the following e-mail address:
567
568 paul@boddie.org.uk
569
570 Copyright and licence information can be found in the docs directory - see
571 docs/COPYING.txt and docs/LICENCE.txt for more information.
572
573 Dependencies
574 ------------
575
576 MoinMessage has the following basic dependencies:
577
578 Packages Release Information
579 -------- -------------------
580
581 MoinSupport Tested with 0.5
582 Source: http://hgweb.boddie.org.uk/MoinSupport