RFC2845 TSIG clarification
I’ve been implementing a variety of RFCs recently. Normally I find them to be quite precise in their definitions - as you’d hope! So I was surprised when I found an (admittedly very small) ambiguity in RFC2845.
RFC2845 deals with TSIG records in the DNS. The idea is that you can append a TSIG signature record to the end of a DNS message. The TSIG RR contains a variety of information about the signature - the time it was computed (plus a fudge factor to account for differing clocks between machines), the name of the key it was signed with, and, amongst other things, the signature itself. A client receiving the message can use its copy of the shared secret key to compute what the signature should be, and compare it with the signature it received. If they match, then it knows that the message is genuine, and has not been tampered with.
Of course, since the TSIG is part of the message which is has just signed, you need to remove the TSIG from the packet, and adjust the header additional record count, before computing the signature. To check that the TSIG record itself has not been tampered with, its attributes (time signed, fudge, key name, etc.) are added to the digest before the signature is computed.
So far, so good.
Sometimes DNS operates in more of a “session” mode. For example, when performing a zone transfer, many DNS messages may need to be exchanged within the context of a single operation. Now these packets could all be signed individually (and it looks like at least one major implementation will do this), but RFC2845 also allows the server to sign only every hundredth message. This uses a different set of data to calculate the signature than the normal (single message) TSIG case. The new set of data includes the digest of the session up to the last TSIG-signed message, as well as all the (unsigned) messages since then. This allows the session as a whole to be verified. The RFC says :
The first envelope is processed as a standard answer, and subsequent messages have the following digest components:
Prior Digest (running)
DNS Messages (any unsigned messages since the last TSIG)
TSIG Timers (current message)
This is fine, so far as it goes. Unfortunately, it doesn’t specify how the current message is to be processed. Should the set of messages so far be added to the prior digest before the current message is processed in the normal manner? Or should the current message be added as is? Should the TSIG variables be processed as in the single message case, or should they be ignored?
What it means is that the current (TSIG signed) message should have the raw bytes stripped of the TSIG record (and the header arcount decremented) before the bytes are added to the set of messages so far. Then the timer values (the time signed and the fudge factor) are added, as they are the only TSIG values to have varied since the first packet (well, the fudge won’t have, but it’s in there anyway).
Very slight ambiguity, admittedly. However, it is the first time that I’ve had to refer to a working implementation before being sure that I knew what the RFC had actually specified!

