From 22b9dc0da3bf4b32f872b0b9ee2c2d30964e7654 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Thu, 16 Jul 2026 12:52:36 +0200 Subject: [PATCH] Fix truncated legacy fingerprint lookup table Legacy session-key renewal could throw IndexOutOfRangeException in FingerprintSubProcedure when a challenge selected the final lookup block. Data2Collection table 1 contained 4222 bytes although its 33 operations require 4224 bytes. Restore the missing final lookup word 0x4C28. The captured renewal challenge 5B15B4694FC38A775E6778F0770C6E7A3118200D now derives fingerprint 6AB5811DE6D28746 and can complete authentication instead of terminating the connection. Add a lookup-table size invariant and an exact regression test for the captured challenge. Bump the package, assembly, and file versions to 1.1.3 and document the fix in the package release notes. --- Directory.Build.props | 10 +++---- .../Fingerprint/HarpoFingerprintTests.cs | 28 ++++++++++++++++++- HarpoS7/Fingerprint/FingerprintConsts.cs | 4 +-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 4630bd8..8434e7f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,11 +11,11 @@ git siemens;s7 - 1.1.2 - 1.1.2 - 1.1.2 - 1.1.2 - Internal naming changes + 1.1.3 + 1.1.3 + 1.1.3 + 1.1.3 + Fix legacy challenge fingerprint derivation for the final lookup-table block. nuget-icon.png diff --git a/HarpoS7.Tests/Fingerprint/HarpoFingerprintTests.cs b/HarpoS7.Tests/Fingerprint/HarpoFingerprintTests.cs index 4b746f9..7ee92fa 100644 --- a/HarpoS7.Tests/Fingerprint/HarpoFingerprintTests.cs +++ b/HarpoS7.Tests/Fingerprint/HarpoFingerprintTests.cs @@ -5,6 +5,32 @@ namespace HarpoS7.Tests.Fingerprint; public class HarpoFingerprintTests { + [Test] + public void LookupTablesCoverEveryComputedBlock() + { + for (var index = 0; index < FingerprintConsts.Data1Collection.Length; index++) + { + var operations = FingerprintConsts.Data1Collection[index].Length / 3; + var requiredBytes = operations * 128; + var availableBytes = FingerprintConsts.Data2Collection[index].Length * sizeof(ushort); + Assert.That( + availableBytes, + Is.GreaterThanOrEqualTo(requiredBytes), + $"Fingerprint table {index} is too short for its computed indices"); + } + } + + [Test] + public void FingerprintChallengeHandlesCapturedLegacyRenewalEdgeCase() + { + Span fingerprint = stackalloc byte[FingerprintConsts.FingerprintLength]; + var challenge = Convert.FromHexString("5B15B4694FC38A775E6778F0770C6E7A3118200D"); + + HarpoFingerprint.FingerprintChallenge(fingerprint, challenge); + + Assert.That(Convert.ToHexString(fingerprint), Is.EqualTo("6AB5811DE6D28746")); + } + public static IEnumerable FingerprintSubProcedureCases { get @@ -1003,4 +1029,4 @@ public void FingerprintChallenge() var expectedFingerprint = new byte[8] { 0xe2, 0x87, 0xc1, 0xcb, 0x65, 0x9b, 0x9e, 0xdf }.AsSpan(); Assert.That(expectedFingerprint.SequenceEqual(fingerprint)); } -} \ No newline at end of file +} diff --git a/HarpoS7/Fingerprint/FingerprintConsts.cs b/HarpoS7/Fingerprint/FingerprintConsts.cs index 719c31c..55850f8 100644 --- a/HarpoS7/Fingerprint/FingerprintConsts.cs +++ b/HarpoS7/Fingerprint/FingerprintConsts.cs @@ -524,7 +524,7 @@ public static class FingerprintConsts 0xd7b1, 0xe73f, 0x7a90, 0xb821, 0xc54b, 0xabd6, 0x7552, 0x4a40, 0xf0d3, 0x2dbf, 0x1fc5, 0xcc99, 0x8111, 0x4305, 0x7080, 0xe835, 0xbf4, 0x43f, 0x6a5f, 0x2ab3, 0xf854, 0x1f7f, 0x3491, 0xd376, 0xd0bb, 0x7bc7, 0xed86, 0x7fbc, 0x2e5b, 0xc137, 0x8bcb, 0xe9ad, 0xb41c, 0xd4ce, 0x77d5, 0xc22f, 0x929f, 0xb6b2, 0xd74f, - 0xe11d, 0xf565, 0x823f, 0x518b, 0xa857, 0xbf08 + 0xe11d, 0xf565, 0x823f, 0x518b, 0xa857, 0xbf08, 0x4c28 }, new ushort[] { @@ -2710,4 +2710,4 @@ public static class FingerprintConsts 0xbc27, 0xf54d, 0x261 }, }; -} \ No newline at end of file +}