From 28008a746a31abb7909dd86cb0cd413ac8943b0b Mon Sep 17 00:00:00 2001 From: jmpoep Date: Thu, 7 Dec 2023 16:51:07 +0800 Subject: first commit --- utils/ipn_tool/CheckSsvTest.cs | 170 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 utils/ipn_tool/CheckSsvTest.cs (limited to 'utils/ipn_tool/CheckSsvTest.cs') diff --git a/utils/ipn_tool/CheckSsvTest.cs b/utils/ipn_tool/CheckSsvTest.cs new file mode 100644 index 0000000..e5a708d --- /dev/null +++ b/utils/ipn_tool/CheckSsvTest.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace ipn_tool +{ + internal static class CheckSsvTest + { + /* GOOD sequence +Taggant Test Application + +Taggant Library version 1 + + + - correct PE file + - taggant is found + - taggant object created + - taggant is correct + - taggant does not contain timestamp + - file protected by packer with 1 id, version .+ + - hashmap covers following regions: +\d.+ any lines + - hashmap is valid + - full file hash is valid + - full file hash covers first \d+ bytes + - SPV Certificate + 30 82 05 5b 30 82 03 43 a0 03 02 01 02 02 10 25 many lines + - User Certificate + 30 82 04 04 30 82 02 ec a0 03 02 01 02 02 10 05 many lines + etc +*/ + internal static int Result(string logFile, string pemFile) + { + var expectedLines = new[] + { + /*00*/ new Regex("^Taggant Test Application$"), + /*01*/ null, + /*02*/ new Regex("^Taggant Library version 1$"), + /*03*/ null, + /*04*/ new Regex(@"^.+"), + /*05*/ new Regex(@"^ - correct PE file$"), + /*06*/ new Regex(@"^ - taggant is found$"), + /*07*/ new Regex(@"^ - taggant object created$"), + /*08*/ new Regex(@"^ - taggant is correct$"), + /*09*/ new Regex(@"^ - taggant does not contain timestamp$"), + /*10*/ new Regex(@"^ - file protected by packer with 1 id, version .+$"), + /*11*/ new Regex(@"^ - hashmap covers following regions:$"), + /*12*/ new Regex(@"^\d.+$"), //any lines + /*13*/ new Regex(@"^ - hashmap is valid$"), + /*14*/ new Regex(@"^ - full file hash is valid$"), + /*15*/ new Regex(@"^ - full file hash covers first \d+ bytes$"), + /*16*/ new Regex(@"^ - SPV Certificate$"), + /*17*/ null, + /*18*/ new Regex(@"^ - User Certificate"), + /*19*/ null + }; + try + { + var stateIndex = 0; + var lineNo = 0; + var spv = new MemoryStream(); + var usr = new MemoryStream(); + var curFile = "unknown"; + foreach (var line in File.ReadAllLines(logFile)) + { + if (stateIndex == 4) + curFile = line; + var re = expectedLines[stateIndex]; + var needCheck = true; + switch (stateIndex) + { + case 13: + needCheck = false; + if (re.IsMatch(line)) + ++stateIndex; + else if (!expectedLines[stateIndex - 1].IsMatch(line)) + throw new InvalidDataException(string.Format("Regex '{0}' or '{1}' match was expected at line #{2} but got '{3}'", re, expectedLines[stateIndex - 1], lineNo, line)); + break; + case 17: + if (!AppendToMemoryStream(line, spv)) + { + stateIndex = 18; + re = expectedLines[stateIndex]; + } + else + { + needCheck = false; + } + break; + case 19: + if (!AppendToMemoryStream(line, usr)) + { + if (!CompareCertificates(pemFile, curFile, spv, usr)) + return 1; + spv = new MemoryStream(); + usr = new MemoryStream(); + stateIndex = 4; + re = expectedLines[stateIndex]; + } + else + { + needCheck = false; + } + break; + } + if(needCheck) + { + if (re == null && line != string.Empty) + throw new InvalidDataException(string.Format("Empty line #{0} was expected but got '{1}'", lineNo, line)); + if (re != null && !re.IsMatch(line)) + throw new InvalidDataException(string.Format("Regex '{0}' match was expected at line #{1} but got '{2}'", re, lineNo, line)); + ++stateIndex; + } + ++lineNo; + } + return CompareCertificates(pemFile, curFile, spv, usr) ? 0 : 1; + } + catch (Exception ex) + { + Console.Error.WriteLine(ex); + return 1; + } + } + + private static bool CompareCertificates(string pemFile, string binaryName, MemoryStream spv, MemoryStream usr) + { + var pemContents = File.ReadAllText(pemFile); + var m = Regex.Match(pemContents, + @"^-----BEGIN CERTIFICATE-----[\s]*(?([^-]+))[\s]*-----END CERTIFICATE-----[\s]*-----BEGIN CERTIFICATE-----[\s]*(?([^-]+))[\s]*-----END CERTIFICATE-----[\s]*-----BEGIN RSA PRIVATE KEY-----[\s]*(?([^-]+))[\s]*-----END RSA PRIVATE KEY-----[\s]*$", + RegexOptions.Multiline); + if (!m.Success) + throw new InvalidDataException("Cannot parse " + pemFile); + var expectedSpv = Convert.FromBase64String(m.Groups["spv"].Value); + var expectedUsr = Convert.FromBase64String(m.Groups["usr"].Value); + //TODO: check private key if need + return CompareBa("SPV", binaryName, expectedSpv, spv.ToArray()) && CompareBa("USER", binaryName, expectedUsr, usr.ToArray()); + } + + private static bool CompareBa(string partName, string binaryName, byte[] p1, byte[] p2) + { + if (p1.Length == p2.Length && p1.Length > 0) + { + for(var i = 0; i < p1.Length; i++) + if (p1[i] != p2[i]) + throw new InvalidDataException(string.Format("taggant.pem {0} did not match to file {1} signature at position {2}.", partName, binaryName, i)); + return true; + } + throw new InvalidDataException(string.Format("taggant.pem {0} did not match to file {1} signature", partName, binaryName)); + } + + // 30 82 05 5b 30 82 03 43 a0 03 02 01 02 02 10 25 - typical line + private static bool AppendToMemoryStream(string line, Stream spv) + { + if (!Regex.IsMatch(line, @"^[\s0-9A-F]+$", RegexOptions.IgnoreCase)) + return false; + var chunk = StringToByteArray(line.Replace(" ", "")); + spv.Write(chunk, 0, chunk.Length); + return true; + } + + private static byte[] StringToByteArray(string hex) + { + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); + } + } +} \ No newline at end of file -- cgit v1.2.3