From cfd8d66e1b170f59aa396c8711feaa72f98c7440 Mon Sep 17 00:00:00 2001 From: Zafer Balkan Date: Fri, 11 Sep 2026 11:49:12 +0300 Subject: [PATCH] Avoid arithmetic failure in TSIG time validation Signed-off-by: Zafer Balkan --- TechnitiumLibrary.Net/Dns/DnsDatagram.cs | 31 ++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/TechnitiumLibrary.Net/Dns/DnsDatagram.cs b/TechnitiumLibrary.Net/Dns/DnsDatagram.cs index 4f22d1b5..a7416e73 100644 --- a/TechnitiumLibrary.Net/Dns/DnsDatagram.cs +++ b/TechnitiumLibrary.Net/Dns/DnsDatagram.cs @@ -1447,11 +1447,9 @@ public bool VerifySignedRequest(IReadOnlyDictionary keys, out D } //Check time values - DateTime startTime = DateTime.UnixEpoch.AddSeconds(tsig.TimeSigned - tsig.Fudge); - DateTime endTime = DateTime.UnixEpoch.AddSeconds(tsig.TimeSigned + tsig.Fudge); DateTime utcNow = DateTime.UtcNow; - if ((utcNow < startTime) || (utcNow > endTime)) + if (!IsTsigTimeValid(tsig.TimeSigned, tsig.Fudge, utcNow)) { unsignedRequest = null; @@ -1474,6 +1472,18 @@ public bool VerifySignedRequest(IReadOnlyDictionary keys, out D return false; } + // RFC 8945 Section 4.2 requires the Error field to be zero in TSIG requests. + // Check it after TSIG validation so malformed authenticated requests receive a signed FORMERR. + if (tsig.Error != DnsTsigError.NoError) + { + unsignedRequest = null; + + errorResponse = new DnsDatagram(_ID, true, _OPCODE, _AA == 1, _TC == 1, _RD == 1, _RA == 1, _AD == 1, _CD == 1, DnsResponseCode.FormatError, _question); + errorResponse = errorResponse.SignResponse(this, keys); + + return false; + } + //return IReadOnlyList additional; @@ -1713,10 +1723,8 @@ public bool VerifySignedResponse(DnsDatagram signedRequest, TsigKey key, out Dns //Check time values DateTime utcNow = DateTime.UtcNow; - DateTime startTime = DateTime.UnixEpoch.AddSeconds(tsig.TimeSigned - tsig.Fudge); - DateTime endTime = DateTime.UnixEpoch.AddSeconds(tsig.TimeSigned + tsig.Fudge); - if ((utcNow < startTime) || (utcNow > endTime)) + if (!IsTsigTimeValid(tsig.TimeSigned, tsig.Fudge, utcNow)) { unsignedResponse = null; requestFailed = false; @@ -1825,10 +1833,7 @@ public bool VerifySignedResponse(DnsDatagram signedRequest, TsigKey key, out Dns } //Check time values - DateTime currentStartTime = DateTime.UnixEpoch.AddSeconds(currentTsig.TimeSigned - currentTsig.Fudge); - DateTime currentEndTime = DateTime.UnixEpoch.AddSeconds(currentTsig.TimeSigned + currentTsig.Fudge); - - if ((utcNow < currentStartTime) || (utcNow > currentEndTime)) + if (!IsTsigTimeValid(currentTsig.TimeSigned, currentTsig.Fudge, utcNow)) { unsignedResponse = null; requestFailed = false; @@ -1913,6 +1918,12 @@ public bool VerifySignedResponse(DnsDatagram signedRequest, TsigKey key, out Dns #region private + private static bool IsTsigTimeValid(ulong timeSigned, ushort fudge, DateTime utcNow) + { + // RFC 8945 Sections 5.2.3 and 5.4.3 require current time to be within Time Signed +/- Fudge. + return Math.Abs((utcNow - DateTime.UnixEpoch).TotalSeconds - timeSigned) <= fudge; + } + private byte[] ComputeTsigRequestMac(string keyName, string algorithmName, ulong timeSigned, ushort fudge, DnsTsigError error, byte[] otherData, string sharedSecret, int truncationLength) { using (MemoryStream mS = new MemoryStream(256))