Re: Some comments on Lua API and a key addressing scheme (in v2.0.0.Beta0)

From: Mark Martinec <>
Date: Fri, 12 Feb 2010 12:50:02 +0100

> > > odkim_get_clienthost(ctx)
> > Having access to the client's IP address (unresolved) would be useful too.
MSK> As a string, I assume? We can add this in time for 2.0.0 since it's
MSK> completely absent.

Yes, as a string is probably the simplest.
It must cover IPv6 addresses as well.

SM> You can access that information with odkim_get_mtasymbol(ctx, name)

True, but by this logic even the odkim_get_clienthost, odkim_get_fromdomain,
and odkim_get_rcpt are redundant. Also, some MTA macros are only available
at certain stages of a SMTP protocol, so I'm not sure which of them would
be accessible to each of the Lua hooks.

> odkim_get_rcpt(ctx, n)
> Returns the nth envelope recipient for the message
why not take advantage of Lua data structures and just return all
recipients in an array? It would look more natural to Lua scripts.

> > > odkim_check_popauth(ctx)
> > > odkim_internal_ip(ctx)
> > > odkim_get_mtasymbol(ctx, name)
> >
> > It could make script's decisions easier if instead (or in addition to)
> > these partial pieces of information the main code would already digest
> > available information and provide information on whether a message
> > is originating from our users, or is inbound. [...]
> Given, as you say, the current implementation offers this piecewise
> rather than in the aggregate, we can consider this for 2.1.0 and leave
> it out of current development. We'd like to get the code as stable as
> possible for this release.

Once an API is established, it is difficult to change it later without
breaking compatibility.

Let me concentrate on one routine only, the odkim_check_popauth.
Considering that sendmail also provides (through macros and milter)
information on SASL authentication and on TLS client certificates,
I consider unwise to provide one specialized API for just one particular
archaic authentication method, but not for other authentication methods.
It will be difficult to get rid of it later, and following its lead
one can imagine a bunch of new functions could be needed for every
niche need.

For signing decisions all that usually matters is whether a roaming
client is authenticated or not. It does not matter what mechanism a
MTA used to establish authentication, and for most practical purposes
a Lua script should not need to be bothered with such peculiarities
of a MTA setup.

So, a routine like some generalized odkim_client_authenticated
returning a boolean would serve Lua scripts better. And if specific
details on the authentication method used are needed (or a need is
discovered later), all it would take is to add another return value
(Lua functions can provide multiple return values) without breaking
existing Lua scripts. So just return a boolean, plus (now or later)
a Lua table with available additional information as key/value pairs.

> > odkim_get_policy(ctx)
> > Returns the discovered Author Domain Signing Practices (ADSP)
> > policy, if one was published and could be retrieved.
> Keep in mind that a message with multiple author addresses in a From
> header field has multiple ADSP policies.
MSK> I'm not too concerned about that for 2.0.0 given how rare a
MSK> multi-address From: header field is. But we can consider it for
MSK> later releases as well.

Once an API is published, it is difficult to change it without breaking
compatibility. Considering that we already know (RFC 5617) that a
message can have multiple ADSP policies, it would be prudent to design
API with this in view. Even if support for multiple author addresses
is not implemented initially or may never be, it would cost practically
nothing to design the API so that it returns an array of policies (or
array of pairs (domain,policy) ) as its result, instead of returning a
scalar. Even a documentational benefit is worth it: script programmers
would be made aware that a message may potentially have multiple policies.

Btw, a policy is preferably not to be queried when there is a valid
author domain signature present, and certainly should have no effect
in such case, so it would make sense to combine the get_policy result
with a presence of an author domain signature and add one additional
possible value to the list:
> These two could be merged into one, returning one of
such as 'unavailable', or better yet: UNAPPLICABLE, so that people
writing Lua scripts won't be lured into consulting or even applying
a policy by mistake when one isn't supposed to be applied.

As a potential source of ideas, please see my documentation for the
DKIM plugin of the SpamAssassin 3.3.0 at:
(in its documentation (POD) section at the beginning of the source code)

In particular the concept of adsp_override domain, a setting
whitelist_from_dkim, and the function check_dkim_adsp() as it is
used in defining certain rules such as DKIM_ADSP_MY1 in the example.

(There is a HTML version of the same POD elsewhere, but it seems some
formatting has been lost there, gluing rules definition into a flowed
text making it difficult to read, sorry, to be fixed.)

> > odkim_sig_ignore(sig)
> I don't see a purpose in this. A missing (ignored) signature is
> equivalent to a failed signature. What good does it do to ignore
> a signature? I can understand it makes perfect sense to ignore
> (or override) an ADSP result, but why invalidate a signature?
> If some signature has no reputation value to a signer, it just
> does not use such reputation in its reputation decisions.
MSK> The library has the capacity to tag a signature to be ignored by
MSK> request of a customer, and this just exposes that library feature
MSK> to the scripts. Since dkim_eom() in the library ultimately returns
MSK> a single good/bad result code based on whether or not there was
MSK> any good signature, this feature influences that value. An
MSK> intelligent caller that wants to check each signature's result
MSK> has that capability as well, but one that wants the library only
MSK> to consider (for example) first-party signatures can arrange that
MSK> dkim_eom()'s return value is predicated solely on such information.

Designing a new API, and even bumping up a major version number,
offer great opportunity to get rid of past sidetracks and hacks
in favour of providing a new API with generalized functionality.
It's worth seizing the opportunity.

Nowadays where each new toy is first adopted by spammers when they
think it may be to their advantage, we can observe that DKIM signing
is more common by spam-spewing throwaway domains than the rest.
So it became very obvious that a mere presence of a valid signature
(first party or not) has no merit by itself without considering its
reputation, or combining it with whitelisting or ADSP.

So what one needs for further decisions on mail fate is the
information on whether a message has an author domain signature or not
(optionally restricted to domains listed as arguments). In addition,
a legitimate question (API) is whether a message has any valid signature
(third party or first party) by any of the listed (as arguments)
signing domains (useful for whitelisting).

Having a function to say that some signature is to be ignored is
a hack to fix a flawed early optimistic thinking that a mere presence
of any valid signature actually means anything. Keeping such function
'for old times sake' only hinders future development - now is
the time to drop it, before even introducing it into a Lua API.
Getting rid if it later will be much more difficult.

> > odkim_add_rcpt(ctx, addr)
> > odkim_del_rcpt(ctx, addr)
> I understand this maps directly to how a milter protocol works,
> but if there is any chance of being able to replace/rewrite a recipient
> address in place, keeping it in its current position in the list, [...]
MSK> I've never heard of an application being aware of or reacting based
MSK> on the order of recipients. Can you give an example of one, and an
MSK> example of why it would matter?

I rest my case here. Keeping the order is not essential, it just looks
ugly to rearrange them without a good reason, when all one intends to do
is to rewrite (reroute) some of the recipient mail addresses.

SM> BTW, the MTA would drop the duplicate addresses on delivery.
SM> Please correct me as I may have got this wrong.

Depends on a MTA and its setting of duplicates elimination.
I don't know if sendmail does duplicates elimination before or after
a milter stage. As its calls to xxfi_envrcpt happen with every
RCPT TO command, I'd expect that duplicates elimination does not
occur yet at this stage.

> Somehow this need to decide aforehand whether a message will be signed
> or verified (or both) rules out the possibility of making a signing
> decision based on results of verification on existing signatures.
> This would be handy with remailers / mailing lists.
MSK> A hook could be added in 2.1.0 for the "final" script that allows
MSK> cancelation of a previous signing request (i.e. a previous call to
MSK> odkim_sign()) if it is observed that any or all of the signatures
MSK> present failed to verify. Would that be satisfactory?

I don't think that is the right approach. Such cancellation would only
be a hack to solve one particular concern. What is needed is a more
flexible solution: completely decouple verification from signing,
always do the verification and ADSP first and provide its results
to a Lua hook, which can then decide not only whether (re)signing
is necessary or not, but also choose an appropriate signing key, a
canonicalization method, a set of field names to sign (the 'h' tag),
identity, and other parameters of a signature, possibly based on
verification/ADSP results.

This would make it possible for example for a mailing list to resign
with a stronger key or with a different identity tag a message received
with a valid signature, or choose another signing parameters
or signing key or a different canonicalization method for resending
other messages, or those violating a mild (ALL) ADSP policy.

Speaking of the 'h' tag, I miss a Lua hook or an extra parameter
to odkim_sign() to be able to dynamically specify which header fields
are to be signed. I also miss the ability to require a signature
(its 'h' tag) to protect certain important header fields (like a From
and Subject) from duplication - see this very message of mine for an
example: Date, Subject, From and Content-Type are being protected,
so that any malicious man-in-the-middle attempt to prepend one of
these header fields and resending the message would invalidate
our signature.

SM> IIRC, there is a flag in opendkim that is used to determine signing
SM> v/s verification. That value could be exposed through a function.
SM> OpenDKIM has a RESIGN feature which can be put to use by forwarders
SM> and mailing lists.
> ResignMailTo (dataset)
> Signs the email, in addition to verifying it, if the message
> recipient is in this set. (Experimental feature not enabled for
> this installation.)
> ResignAll (boolean)
> Resign everything if set, verified mail only if not, defaults to
> false. (Experimental feature not enabled for this installation.)
> odkim_resign(ctx)
> Arranges that the arriving message will be verified and then re-
> signed in a single operation. Returns 1 on success or the Lua
> constant "nil" on failure.

In view of my claim above, I think the odkim_resign() should be dropped now
before even introducing it to API, in favour of a verify -> lua -> sign

> [...] it is preferable to devise an API and/or a database schema
> in such a way that the situation cannot occur at all.
SM> Yes. We came across a few cases like that. If we key on the
SM> selector/domain, we can avoid such mistakes.
SM> If I am not mistaken, OpenDKIM will be doing mapping through
SM> selector/domain.


(more on designing a LDAP schema is on my mind, having to do a similar
quantum leap to LDAP with my next version of amavisd-new, but let me
leave it to some other posting, this one is already fully loaded with
concepts :)

Received on Fri Feb 12 2010 - 11:50:20 PST

This archive was generated by hypermail 2.3.0 : Mon Oct 29 2012 - 23:19:46 PST