This week things moved along with the mailman-pgp plugin. As I finally had a good PGP library to work with as well as some basic plugin API patches outstanding to Mailman Core.
So with that I implemented large parts of the
mailman_pgp.pgp package, including tests, as well as a basic signature checking rule. Also, as the package now contains tests, I added a gitlab CI config and started running it.
Created two classes, which wrap an
email.message.Message instance (or
mailman.email.message.Message) and expose a common public PGP handling API on said instance. One understands PGP/MIME (as per RFC1847 and RFC3156) and the other somewhat understands inline PGP. They both give methods to check presence of a PGP signed/encrypted message or PGP keys, to verify signatures of a message, to decrypt it or collect the attached keys. There are currently almost complete tests for handling signatures and partial for encryption.
This one was rather easy to implement, as RFC3156 and RFC1847 are both very precise but also rather simple standards (well compared that to 90+ page RFC4880 [OpenPGP]).
As there is really no “Inline PGP standard” this wrapper improvises with how it looks for signatures/messages/keys. In it’s current form it only accepts a non-multipart message and looks for ASCII-armored blobs in it.
The concrete way of integrating the PGP plugin into Mailman Core has changed over time. The original version of my proposal planned on working in the Mailman Core tree and as that changed to a plugin, new requirements of integration popped up, us stuff couldn’t just be changed for this one plugin to work.
Because of the nature of encryption the PGP plugin needs to get it’s hands on the messages before the rest of Mailmans rules. This could be done with a rule in a custom chain, however as I understand rules, they are, well, rules, they shouldn’t change the message they are processing in any way. In my understanding of this architecture, if Mailman was written in a language with a
const identifier, the message would have it in the chain links
process method. It would work as a rule, just wouldn’t feel nice and fit in with the architecture.
That’s why I first wanted to implement all handling of incoming messages in a custom incoming runner. This runners class is then set as the runner for the
in queue and the default runner is moved to another queue, perhaps
in_default. The custom incoming runner does it’s thing before passing messages back to the default incoming runners queue. However only encryption has this issue of needing to change the message, as rules and the rest need it in cleartext. So I decided to split off signature handling to a custom rule, and only handle encryption in the incoming runner.
I would like to get rid of the not-so-nice redirection of the default incoming runner altogether but I see no other way to decrypt the incoming message to a PGP enabled list before other rules get it.
The signature rule processes messages using the wrappers described above according to a per-list signature handling configuration:
I think the options are quite self-explanatory. They are checked in order and taken if the message matches the option and the set action is not
None. So with the default configuration of the PGP enabled mailing list, an unsigned message will be bounced, inline PGP is allowed, signatures by expired keys are bounced (expired at time of checking), signatures by revoked keys are bounced, signatures that don’t verify are bounced (maybe a better name for them than malformed?) and finally signatures that the Mailman PGP plugin already processed are bounced as well. This is to prevent replay attacks and is something I think people would expect Mailman to do, although I am not sure if the plugin should do it.
This signature rule is almost complete, with some edge-cases remaining and the checking of duplicate signatures also remaining.