Conversation
Signed-off-by: Zafer Balkan <zafer@zaferbalkan.com>
Member
|
Thanks for the PR. Will check it soon in detail. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This PR makes two related fixes to TSIG (RFC 8945) message verification in
DnsDatagram.cs.First, it replaces the arithmetic used to check a TSIG record's time window. The previous code built
DateTimevalues by callingDateTime.UnixEpoch.AddSeconds(tsig.TimeSigned - tsig.Fudge)and the+tsig.Fudgeequivalent, then compared them againstDateTime.UtcNow. BecauseTimeSignedis an unsigned 48-bit value carried in aulongandFudgeis aushort, a crafted or corrupted combination of the two can push the computed seconds-since-epoch outside the rangeDateTimecan represent, which makesAddSecondsthrowArgumentOutOfRangeException. This is now a private helper,IsTsigTimeValid, that does the whole comparison indoublearithmetic (Math.Abs((utcNow - DateTime.UnixEpoch).TotalSeconds - timeSigned) <= fudge) and can't overflow. The three call sites — request verification, response verification, and the intermediate-message verification loop for multi-message TSIG chains — all now go through this one helper instead of duplicating the old inline logic.Second, it adds a check in
VerifySignedRequestthat rejects a request whose TSIGErrorfield is non-zero. RFC 8945 §4.2 is explicit here: "Error: in responses, an unsigned 16-bit integer containing the extended RCODE covering TSIG processing. In requests, this MUST be zero." A non-zeroErroron an inbound request is therefore a malformed message, and the code now returns a signedFORMERRresponse for it, the same way it already does forBADTIME/BADTRUNC.Why
The time-validation change closes a remote crash vector: any signed request or response whose
TimeSigned/Fudgepair produces an out-of-rangeDateTimeadd can throw before the record's authenticity has even been checked, i.e. before the library knows whether the sender holds a valid key. That's a denial-of-service condition triggerable by anyone who can reach the TSIG-verification code path, not just an authenticated peer.The
Error-field change brings request verification in line with what the RFC actually specifies, rather than silently accepting a field value the spec reserves for responses only. It's a small conformance gap, not a security hole on its own, but it's the kind of gap that lets a malformed or buggy client interoperate today and fail unpredictably against a stricter implementation later.How
IsTsigTimeValid(ulong timeSigned, ushort fudge, DateTime utcNow)is added as a private static method and used to replace three duplicated inline blocks (request verification, response verification, and the chained-message loop for TCP AXFR-style multi-message TSIG). No public API surface changes — the three call sites keep the exact same branching and error responses they had before (BADTIMEsigned responses, etc.); only the comparison itself changed.The
Error != NoErrorcheck is inserted intoVerifySignedRequestafter the MAC, time, and truncation checks succeed, so it only fires once the request has already been authenticated with a valid key. That ordering matters: it means the rejection is deliberately signed (errorResponse.SignResponse(this, keys)), consistent with howBADTIMEandBADTRUNCare already handled in that method, rather than falling back to the unsigned path used for key/signature failures where the key hasn't yet been proven valid.I deliberately did not add a companion check on
OtherData. RFC 8945 §4.2 says "[Other Data] This document assigns no meaning to its contents in requests" — unlikeError, there's no MUST-be-empty requirement forOtherDataon the request side, so enforcing one would be a spec violation in the other direction.Testing
dotnet build TechnitiumLibrary.Net/TechnitiumLibrary.Net.csproj -c Release— builds clean, 0 warnings/errors.IsTsigTimeValidcall sites against the original inequality semantics to confirm no behavioral drift versus the pre-existing logic (same bounds, same inclusive<=/>=comparison, just no overflow path).zbalkan/DnsServer: built this branch'sTechnitiumLibrary.Net.dlland rebuiltDnsServerCore.csprojand the fullDnsServerApp.csprojagainst it — both succeed with 0 errors. The sole call site ofVerifySignedRequestinDnsServer.csalready branches generically on the boolean result and logserrorResponse.RCODE/TsigError, so the newFormatErrorpath requires no change there. DnsServer's own outbound signed requests (zone transfer, refresh, notify) go through the library'sTsigResolveAsync → SignRequest, which always hardcodesError = NoError, so this server can't trip its own new check.Anything Else
Not blocking this PR, but worth a follow-up issue: there's no test project in
TechnitiumLibraryat all. TSIG verification is exactly the kind of logic (bit-width edge cases, RFC-mandated field checks) that benefits from a small table-driven test suite — this PR would have been a good candidate to introduce one, but that's a larger, separate undertaking than these two bug fixes.