From 1c596661b7423a2d9f49869a795caf7f8ceabd90 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Fri, 28 May 2021 17:52:35 -0400
Subject: [PATCH 01/19] * add pkcs nuget dependency * rename checkers ->
Checkers * add SignedFile verifier and use it to verify the signed file
---
.gitignore | 2 +-
ZitiUpdateService/UpdateService.cs | 15 +-
ZitiUpdateService/ZitiUpdateService.csproj | 8 +
ZitiUpdateService/checkers/FilesystemCheck.cs | 6 +-
ZitiUpdateService/checkers/GithubCheck.cs | 5 +-
.../checkers/PeFile/SignedFileStructs.cs | 539 ++++++++++++++++++
.../checkers/PeFile/SignedFileValidator.cs | 344 +++++++++++
.../checkers/PeFile/StructHelper.cs | 17 +
ZitiUpdateService/checkers/UpdateCheckers.cs | 2 +-
ZitiUpdateService/packages.config | 3 +-
10 files changed, 925 insertions(+), 16 deletions(-)
create mode 100644 ZitiUpdateService/checkers/PeFile/SignedFileStructs.cs
create mode 100644 ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
create mode 100644 ZitiUpdateService/checkers/PeFile/StructHelper.cs
diff --git a/.gitignore b/.gitignore
index 9312a38f..cfec3e2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -268,7 +268,7 @@ service/libuv.dll
Installer/build/
Installer/ziti-tunnel-service.zip
ziti-tunnel-service.zip
-WinSign.p12
+WinSign.*
*.p12
*.pfx
*.pem
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index bfd6e615..59f7b246 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -19,6 +19,7 @@ using NLog;
using Newtonsoft.Json;
using System.Net;
using DnsClient;
+using ZitiUpdateService.Checkers.PeFile;
namespace ZitiUpdateService {
public partial class UpdateService : ServiceBase {
@@ -54,7 +55,7 @@ namespace ZitiUpdateService {
IPCServer svr = new IPCServer();
Task ipcServer = null;
Task eventServer = null;
- checkers.UpdateCheck check = null;
+ Checkers.UpdateCheck check = null;
private Timer dnsProbeTimer = new Timer();
private IPAddress dnsIpAddress = null;
@@ -574,9 +575,9 @@ namespace ZitiUpdateService {
updateUrl = "https://api.github.com/repos/openziti/desktop-edge-win-beta/releases/latest";
}
if (useGithubCheck) {
- check = new checkers.GithubCheck(updateUrl);
+ check = new Checkers.GithubCheck(updateUrl);
} else {
- check = new checkers.FilesystemCheck(1);
+ check = new Checkers.FilesystemCheck(1);
}
}
@@ -605,7 +606,7 @@ namespace ZitiUpdateService {
Logger.Warn("Still in update check. This is abnormal. Please report if you see this warning");
return;
}
- inUpdateCheck = true; //simple semaphone
+ inUpdateCheck = true; //simple semaphore
try {
Logger.Debug("checking for update");
@@ -626,8 +627,8 @@ namespace ZitiUpdateService {
string fileDestination = Path.Combine(updateFolder, filename);
if (check.AlreadyDownloaded(updateFolder, filename)) {
- Logger.Info("package has already been downloaded to {0} - moving to install phase", Path.Combine(updateFolder, filename));
- } else {
+ Logger.Info("package has already been downloaded to {0} - moving to install phase", fileDestination);
+ } else {
Logger.Info("copying update package begins");
check.CopyUpdatePackage(updateFolder, filename);
Logger.Info("copying update package complete");
@@ -641,6 +642,8 @@ namespace ZitiUpdateService {
}
Logger.Debug("downloaded file hash was correct. update can continue.");
+ new SignedFileValidator(fileDestination).Verify();
+
// check digital signature
var signer = X509Certificate.CreateFromSignedFile(fileDestination);
/* keep these commented out lines - just in case we need all the certs from the file use this
diff --git a/ZitiUpdateService/ZitiUpdateService.csproj b/ZitiUpdateService/ZitiUpdateService.csproj
index cbb3bf6a..6f14703f 100644
--- a/ZitiUpdateService/ZitiUpdateService.csproj
+++ b/ZitiUpdateService/ZitiUpdateService.csproj
@@ -99,6 +99,10 @@
..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll
+
+
+ ..\packages\System.Security.Cryptography.Pkcs.5.0.1\lib\net461\System.Security.Cryptography.Pkcs.dll
+
@@ -113,6 +117,9 @@
+
+
+
Component
@@ -170,5 +177,6 @@
ZitiDesktopEdge.Client
+
\ No newline at end of file
diff --git a/ZitiUpdateService/checkers/FilesystemCheck.cs b/ZitiUpdateService/checkers/FilesystemCheck.cs
index 6d0d456e..ef56ad32 100644
--- a/ZitiUpdateService/checkers/FilesystemCheck.cs
+++ b/ZitiUpdateService/checkers/FilesystemCheck.cs
@@ -1,13 +1,9 @@
using System;
using System.IO;
-using System.Net;
-
-using System.Security.Cryptography;
using NLog;
-using Newtonsoft.Json.Linq;
-namespace ZitiUpdateService.checkers {
+namespace ZitiUpdateService.Checkers {
internal class FilesystemCheck : UpdateCheck {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
string dest = null;
diff --git a/ZitiUpdateService/checkers/GithubCheck.cs b/ZitiUpdateService/checkers/GithubCheck.cs
index eeca9452..37512d30 100644
--- a/ZitiUpdateService/checkers/GithubCheck.cs
+++ b/ZitiUpdateService/checkers/GithubCheck.cs
@@ -7,8 +7,9 @@ using NLog;
using Newtonsoft.Json.Linq;
using ZitiDesktopEdge.Utility;
+using ZitiUpdateService.Checkers.PeFile;
-namespace ZitiUpdateService.checkers {
+namespace ZitiUpdateService.Checkers {
internal class GithubCheck : UpdateCheck {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
@@ -97,7 +98,7 @@ namespace ZitiUpdateService.checkers {
File.Delete(sha256dest);
return computed.ToLower().Trim() == hash.ToLower().Trim();
}
- }
+ }
override public Version GetNextVersion() {
return nextVersion;
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileStructs.cs b/ZitiUpdateService/checkers/PeFile/SignedFileStructs.cs
new file mode 100644
index 00000000..ce1d2cc9
--- /dev/null
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileStructs.cs
@@ -0,0 +1,539 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ZitiUpdateService.Checkers.PeFile {
+
+ //defined by http://www.pinvoke.net/default.aspx/Structures/IMAGE_FILE_HEADER.html
+ [StructLayout(LayoutKind.Sequential)]
+ public struct IMAGE_FILE_HEADER {
+ public UInt16 Machine;
+ public UInt16 NumberOfSections;
+ public UInt32 TimeDateStamp;
+ public UInt32 PointerToSymbolTable;
+ public UInt32 NumberOfSymbols;
+ public UInt16 SizeOfOptionalHeader;
+ public UInt16 Characteristics;
+ }
+
+ //see http://www.pinvoke.net/default.aspx/Structures/IMAGE_OPTIONAL_HEADER32.html
+ //defined by http://www.pinvoke.net/default.aspx/Structures/IMAGE_OPTIONAL_HEADER32.html
+ [StructLayout(LayoutKind.Sequential)]
+ public struct IMAGE_DATA_DIRECTORY {
+ public UInt32 VirtualAddress;
+ public UInt32 Size;
+ }
+
+ public enum MachineType : ushort {
+ Native = 0,
+ I386 = 0x014c,
+ Itanium = 0x0200,
+ x64 = 0x8664
+ }
+
+ public sealed class MagicType {
+ public const Int16 IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
+ public const Int16 IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
+ }
+
+ public enum SubSystemType : ushort {
+ IMAGE_SUBSYSTEM_UNKNOWN = 0,
+ IMAGE_SUBSYSTEM_NATIVE = 1,
+ IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
+ IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
+ IMAGE_SUBSYSTEM_POSIX_CUI = 7,
+ IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9,
+ IMAGE_SUBSYSTEM_EFI_APPLICATION = 10,
+ IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
+ IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
+ IMAGE_SUBSYSTEM_EFI_ROM = 13,
+ IMAGE_SUBSYSTEM_XBOX = 14
+
+ }
+
+ public enum DllCharacteristicsType : ushort {
+ RES_0 = 0x0001,
+ RES_1 = 0x0002,
+ RES_2 = 0x0004,
+ RES_3 = 0x0008,
+ IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040,
+ IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
+ IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100,
+ IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
+ IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
+ IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
+ RES_4 = 0x1000,
+ IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
+ IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct IMAGE_OPTIONAL_HEADER32 {
+ [FieldOffset(0)] public ushort Magic;
+
+ [FieldOffset(2)] public byte MajorLinkerVersion;
+
+ [FieldOffset(3)] public byte MinorLinkerVersion;
+
+ [FieldOffset(4)] public uint SizeOfCode;
+
+ [FieldOffset(8)] public uint SizeOfInitializedData;
+
+ [FieldOffset(12)] public uint SizeOfUninitializedData;
+
+ [FieldOffset(16)] public uint AddressOfEntryPoint;
+
+ [FieldOffset(20)] public uint BaseOfCode;
+
+ // PE32 contains this additional field
+ [FieldOffset(24)] public uint BaseOfData;
+
+ [FieldOffset(28)] public uint ImageBase;
+
+ [FieldOffset(32)] public uint SectionAlignment;
+
+ [FieldOffset(36)] public uint FileAlignment;
+
+ [FieldOffset(40)] public ushort MajorOperatingSystemVersion;
+
+ [FieldOffset(42)] public ushort MinorOperatingSystemVersion;
+
+ [FieldOffset(44)] public ushort MajorImageVersion;
+
+ [FieldOffset(46)] public ushort MinorImageVersion;
+
+ [FieldOffset(48)] public ushort MajorSubsystemVersion;
+
+ [FieldOffset(50)] public ushort MinorSubsystemVersion;
+
+ [FieldOffset(52)] public uint Win32VersionValue;
+
+ [FieldOffset(56)] public uint SizeOfImage;
+
+ [FieldOffset(60)] public uint SizeOfHeaders;
+
+ [FieldOffset(64)] public uint CheckSum;
+
+ [FieldOffset(68)] public SubSystemType Subsystem;
+
+ [FieldOffset(70)] public DllCharacteristicsType DllCharacteristics;
+
+ [FieldOffset(72)] public uint SizeOfStackReserve;
+
+ [FieldOffset(76)] public uint SizeOfStackCommit;
+
+ [FieldOffset(80)] public uint SizeOfHeapReserve;
+
+ [FieldOffset(84)] public uint SizeOfHeapCommit;
+
+ [FieldOffset(88)] public uint LoaderFlags;
+
+ [FieldOffset(92)] public uint NumberOfRvaAndSizes;
+
+ [FieldOffset(96)] public IMAGE_DATA_DIRECTORY ExportTable;
+
+ [FieldOffset(104)] public IMAGE_DATA_DIRECTORY ImportTable;
+
+ [FieldOffset(112)] public IMAGE_DATA_DIRECTORY ResourceTable;
+
+ [FieldOffset(120)] public IMAGE_DATA_DIRECTORY ExceptionTable;
+
+ [FieldOffset(128)] public IMAGE_DATA_DIRECTORY CertificateTable;
+
+ [FieldOffset(136)] public IMAGE_DATA_DIRECTORY BaseRelocationTable;
+
+ [FieldOffset(144)] public IMAGE_DATA_DIRECTORY Debug;
+
+ [FieldOffset(152)] public IMAGE_DATA_DIRECTORY Architecture;
+
+ [FieldOffset(160)] public IMAGE_DATA_DIRECTORY GlobalPtr;
+
+ [FieldOffset(168)] public IMAGE_DATA_DIRECTORY TLSTable;
+
+ [FieldOffset(176)] public IMAGE_DATA_DIRECTORY LoadConfigTable;
+
+ [FieldOffset(184)] public IMAGE_DATA_DIRECTORY BoundImport;
+
+ [FieldOffset(192)] public IMAGE_DATA_DIRECTORY IAT;
+
+ [FieldOffset(200)] public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
+
+ [FieldOffset(208)] public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
+
+ [FieldOffset(216)] public IMAGE_DATA_DIRECTORY Reserved;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct IMAGE_OPTIONAL_HEADER64 {
+ [FieldOffset(0)] public ushort Magic;
+
+ [FieldOffset(2)] public byte MajorLinkerVersion;
+
+ [FieldOffset(3)] public byte MinorLinkerVersion;
+
+ [FieldOffset(4)] public uint SizeOfCode;
+
+ [FieldOffset(8)] public uint SizeOfInitializedData;
+
+ [FieldOffset(12)] public uint SizeOfUninitializedData;
+
+ [FieldOffset(16)] public uint AddressOfEntryPoint;
+
+ [FieldOffset(20)] public uint BaseOfCode;
+
+ [FieldOffset(24)] public ulong ImageBase;
+
+ [FieldOffset(32)] public uint SectionAlignment;
+
+ [FieldOffset(36)] public uint FileAlignment;
+
+ [FieldOffset(40)] public ushort MajorOperatingSystemVersion;
+
+ [FieldOffset(42)] public ushort MinorOperatingSystemVersion;
+
+ [FieldOffset(44)] public ushort MajorImageVersion;
+
+ [FieldOffset(46)] public ushort MinorImageVersion;
+
+ [FieldOffset(48)] public ushort MajorSubsystemVersion;
+
+ [FieldOffset(50)] public ushort MinorSubsystemVersion;
+
+ [FieldOffset(52)] public uint Win32VersionValue;
+
+ [FieldOffset(56)] public uint SizeOfImage;
+
+ [FieldOffset(60)] public uint SizeOfHeaders;
+
+ [FieldOffset(64)] public uint CheckSum;
+
+ [FieldOffset(68)] public SubSystemType Subsystem;
+
+ [FieldOffset(70)] public DllCharacteristicsType DllCharacteristics;
+
+ [FieldOffset(72)] public ulong SizeOfStackReserve;
+
+ [FieldOffset(80)] public ulong SizeOfStackCommit;
+
+ [FieldOffset(88)] public ulong SizeOfHeapReserve;
+
+ [FieldOffset(96)] public ulong SizeOfHeapCommit;
+
+ [FieldOffset(104)] public uint LoaderFlags;
+
+ [FieldOffset(108)] public uint NumberOfRvaAndSizes;
+
+ [FieldOffset(112)] public IMAGE_DATA_DIRECTORY ExportTable;
+
+ [FieldOffset(120)] public IMAGE_DATA_DIRECTORY ImportTable;
+
+ [FieldOffset(128)] public IMAGE_DATA_DIRECTORY ResourceTable;
+
+ [FieldOffset(136)] public IMAGE_DATA_DIRECTORY ExceptionTable;
+
+ [FieldOffset(144)] public IMAGE_DATA_DIRECTORY CertificateTable;
+
+ [FieldOffset(152)] public IMAGE_DATA_DIRECTORY BaseRelocationTable;
+
+ [FieldOffset(160)] public IMAGE_DATA_DIRECTORY Debug;
+
+ [FieldOffset(168)] public IMAGE_DATA_DIRECTORY Architecture;
+
+ [FieldOffset(176)] public IMAGE_DATA_DIRECTORY GlobalPtr;
+
+ [FieldOffset(184)] public IMAGE_DATA_DIRECTORY TLSTable;
+
+ [FieldOffset(192)] public IMAGE_DATA_DIRECTORY LoadConfigTable;
+
+ [FieldOffset(200)] public IMAGE_DATA_DIRECTORY BoundImport;
+
+ [FieldOffset(208)] public IMAGE_DATA_DIRECTORY IAT;
+
+ [FieldOffset(216)] public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
+
+ [FieldOffset(224)] public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
+
+ [FieldOffset(232)] public IMAGE_DATA_DIRECTORY Reserved;
+ }
+
+
+ [StructLayout(LayoutKind.Explicit)]
+ public struct IMAGE_SECTION_HEADER {
+ //FROM: http://www.pinvoke.net/default.aspx/Structures/IMAGE_SECTION_HEADER.html
+ [FieldOffset(0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ public char[] Name;
+
+ [FieldOffset(8)] public UInt32 VirtualSize;
+
+ [FieldOffset(12)] public UInt32 VirtualAddress;
+
+ [FieldOffset(16)] public UInt32 SizeOfRawData;
+
+ [FieldOffset(20)] public UInt32 PointerToRawData;
+
+ [FieldOffset(24)] public UInt32 PointerToRelocations;
+
+ [FieldOffset(28)] public UInt32 PointerToLinenumbers;
+
+ [FieldOffset(32)] public UInt16 NumberOfRelocations;
+
+ [FieldOffset(34)] public UInt16 NumberOfLinenumbers;
+
+ [FieldOffset(36)] public DataSectionFlags Characteristics;
+
+ public string Section {
+ get { return new string(Name); }
+ }
+ }
+
+ [Flags]
+ public enum DataSectionFlags : uint {
+ //FROM: http://www.pinvoke.net/default.aspx/Structures/IMAGE_SECTION_HEADER.html
+ ///
+ /// Reserved for future use.
+ ///
+ TypeReg = 0x00000000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeDsect = 0x00000001,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeNoLoad = 0x00000002,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeGroup = 0x00000004,
+
+ ///
+ /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.
+ ///
+ TypeNoPadded = 0x00000008,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeCopy = 0x00000010,
+
+ ///
+ /// The section contains executable code.
+ ///
+ ContentCode = 0x00000020,
+
+ ///
+ /// The section contains initialized data.
+ ///
+ ContentInitializedData = 0x00000040,
+
+ ///
+ /// The section contains uninitialized data.
+ ///
+ ContentUninitializedData = 0x00000080,
+
+ ///
+ /// Reserved for future use.
+ ///
+ LinkOther = 0x00000100,
+
+ ///
+ /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
+ ///
+ LinkInfo = 0x00000200,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeOver = 0x00000400,
+
+ ///
+ /// The section will not become part of the image. This is valid only for object files.
+ ///
+ LinkRemove = 0x00000800,
+
+ ///
+ /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files.
+ ///
+ LinkComDat = 0x00001000,
+
+ ///
+ /// Reset speculative exceptions handling bits in the TLB entries for this section.
+ ///
+ NoDeferSpecExceptions = 0x00004000,
+
+ ///
+ /// The section contains data referenced through the global pointer (GP).
+ ///
+ RelativeGP = 0x00008000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemPurgeable = 0x00020000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ Memory16Bit = 0x00020000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemoryLocked = 0x00040000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemoryPreload = 0x00080000,
+
+ ///
+ /// Align data on a 1-byte boundary. Valid only for object files.
+ ///
+ Align1Bytes = 0x00100000,
+
+ ///
+ /// Align data on a 2-byte boundary. Valid only for object files.
+ ///
+ Align2Bytes = 0x00200000,
+
+ ///
+ /// Align data on a 4-byte boundary. Valid only for object files.
+ ///
+ Align4Bytes = 0x00300000,
+
+ ///
+ /// Align data on an 8-byte boundary. Valid only for object files.
+ ///
+ Align8Bytes = 0x00400000,
+
+ ///
+ /// Align data on a 16-byte boundary. Valid only for object files.
+ ///
+ Align16Bytes = 0x00500000,
+
+ ///
+ /// Align data on a 32-byte boundary. Valid only for object files.
+ ///
+ Align32Bytes = 0x00600000,
+
+ ///
+ /// Align data on a 64-byte boundary. Valid only for object files.
+ ///
+ Align64Bytes = 0x00700000,
+
+ ///
+ /// Align data on a 128-byte boundary. Valid only for object files.
+ ///
+ Align128Bytes = 0x00800000,
+
+ ///
+ /// Align data on a 256-byte boundary. Valid only for object files.
+ ///
+ Align256Bytes = 0x00900000,
+
+ ///
+ /// Align data on a 512-byte boundary. Valid only for object files.
+ ///
+ Align512Bytes = 0x00A00000,
+
+ ///
+ /// Align data on a 1024-byte boundary. Valid only for object files.
+ ///
+ Align1024Bytes = 0x00B00000,
+
+ ///
+ /// Align data on a 2048-byte boundary. Valid only for object files.
+ ///
+ Align2048Bytes = 0x00C00000,
+
+ ///
+ /// Align data on a 4096-byte boundary. Valid only for object files.
+ ///
+ Align4096Bytes = 0x00D00000,
+
+ ///
+ /// Align data on an 8192-byte boundary. Valid only for object files.
+ ///
+ Align8192Bytes = 0x00E00000,
+
+ ///
+ /// The section contains extended relocations.
+ ///
+ LinkExtendedRelocationOverflow = 0x01000000,
+
+ ///
+ /// The section can be discarded as needed.
+ ///
+ MemoryDiscardable = 0x02000000,
+
+ ///
+ /// The section cannot be cached.
+ ///
+ MemoryNotCached = 0x04000000,
+
+ ///
+ /// The section is not pageable.
+ ///
+ MemoryNotPaged = 0x08000000,
+
+ ///
+ /// The section can be shared in memory.
+ ///
+ MemoryShared = 0x10000000,
+
+ ///
+ /// The section can be executed as code.
+ ///
+ MemoryExecute = 0x20000000,
+
+ ///
+ /// The section can be read.
+ ///
+ MemoryRead = 0x40000000,
+
+ ///
+ /// The section can be written to.
+ ///
+ MemoryWrite = 0x80000000
+ }
+
+
+ public class ImageOptionalHeaderWrapper {
+ public IMAGE_OPTIONAL_HEADER32 h32;
+ public IMAGE_OPTIONAL_HEADER64 h64;
+ public bool IsPe;
+
+
+ public uint CertificateTableVirtualAddress {
+ get {
+ if (IsPe) {
+ return h32.CertificateTable.VirtualAddress;
+ } else {
+ return h64.CertificateTable.VirtualAddress;
+ }
+ }
+ }
+
+ public uint CertificateTableSize {
+ get {
+ if (IsPe) {
+ return h32.CertificateTable.Size;
+ } else {
+ return h64.CertificateTable.Size;
+ }
+ }
+ }
+
+ public uint SizeOfHeaders {
+ get {
+ if (IsPe) {
+ return h32.SizeOfHeaders;
+ } else {
+ return h64.SizeOfHeaders;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
new file mode 100644
index 00000000..8691f8f6
--- /dev/null
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -0,0 +1,344 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Pkcs;
+
+namespace ZitiUpdateService.Checkers.PeFile {
+ public class SignedFileValidator {
+ public const int LengthOfChecksum = 4; //the checksum is 4 bytes
+ public const int LenghtCertificateTable = 8; //the Certificate Table is 8 bytes
+
+ public HashPositions ImportantHashPositions { get; private set; }
+ public string FilePath { get; private set; }
+ public PeType Type { get; private set; }
+ public IMAGE_FILE_HEADER CoffHeader { get; private set; }
+ public IMAGE_OPTIONAL_HEADER32 StandardFieldsPe32 { get; private set; }
+ public IMAGE_OPTIONAL_HEADER64 StandardFieldsPe32Plus { get; private set; }
+ public SignedFileValidator(string pathToFile) {
+ FilePath = pathToFile;
+ ImportantHashPositions = new HashPositions();
+
+ parse();
+ if (ImportantHashPositions.reorderNeeded) {
+ ImportantHashPositions.SectionTableHeaders.Sort((x, y) => x.PointerToRawData.CompareTo(y.PointerToRawData));
+ }
+ }
+
+ // ReSharper disable once InconsistentNaming
+ private void parse() {
+ using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+
+ //seek to 0x3c to get right to the PE header location...
+ stream.Seek(0x3c, SeekOrigin.Begin);
+ uint startCoffHeader = BitConverter.ToUInt32(reader.ReadBytes(4), 0);
+ ImportantHashPositions.SetStartCoffHeader(startCoffHeader);
+ stream.Seek(startCoffHeader, SeekOrigin.Begin);
+
+ //parse COFF Header (28 or 24 bytes): https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image
+ byte[] coffHeaderBytes = reader.ReadBytes(24);
+ CoffHeader = StructHelper.FromBytes(coffHeaderBytes);
+
+ byte[] magicNumberBytes = reader.ReadBytes(2);
+ int magicNumber = BitConverter.ToInt16(magicNumberBytes, 0);
+ Type = magicNumber == 0x10b ? PeType.Pe32 : PeType.Pe32Plus;
+ stream.Seek(-2, SeekOrigin.Current); //skip back to before the magic number so the struct below is created properly
+
+ //parse Optional Header Standard and Windows-Specific fields (66 or 88 bytes)
+ //see: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-standard-fields-image-only
+ if (Type == PeType.Pe32) {
+ byte[] headerBytes = reader.ReadBytes(Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32)));
+ StandardFieldsPe32 = StructHelper.FromBytes(headerBytes);
+ } else {
+ byte[] headerBytes = reader.ReadBytes(Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER64)));
+ StandardFieldsPe32Plus = StructHelper.FromBytes(headerBytes);
+ }
+
+ ImageOptionalHeaderWrapper wrapper = new ImageOptionalHeaderWrapper() {
+ h32 = StandardFieldsPe32,
+ h64 = StandardFieldsPe32Plus,
+ IsPe = Type == PeType.Pe32
+ };
+ ImportantHashPositions.SetCertificateDetails(Type, wrapper.SizeOfHeaders, wrapper.CertificateTableVirtualAddress, wrapper.CertificateTableSize);
+
+ for (int i = 0; i < CoffHeader.NumberOfSections; i++) {
+ byte[] nextSection = reader.ReadBytes(Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER))); //should be 40 bytes...
+ IMAGE_SECTION_HEADER sectionTableHeader = StructHelper.FromBytes(nextSection);
+ ImportantHashPositions.AddSectionTableHeader(sectionTableHeader);
+ }
+ }
+ }
+
+ public void Verify() {
+ using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+ //verify all the embedded signatures
+ stream.Seek(this.ImportantHashPositions.CertificateTableStart, SeekOrigin.Begin);
+ int readCertLen = reader.ReadInt32();
+ int readRevision = reader.ReadInt16();
+ int readCertType = reader.ReadInt16();
+ byte[] pkcs7 = reader.ReadBytes(readCertLen);
+
+ SignedCms cms = new SignedCms();
+ cms.Decode(pkcs7);
+ cms.CheckHash();
+ //shout out to Scott MG: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/655f5c27-b049-4275-a8b3-cc1c0be2b4f2/retrieve-certificate-info-for-dualsigned-sha1sha256
+ //for indicating that the unsigned attributes contain the other fingerprints
+ if (cms.SignerInfos.Count > 0) {
+ SignerInfo si = cms.SignerInfos[0];
+ si.CheckSignature(true);
+ if (cms.SignerInfos[0] != null && cms.SignerInfos[0].UnsignedAttributes.Count > 0) {
+ foreach (AsnEncodedData asn in cms.SignerInfos[0].UnsignedAttributes[0].Values) {
+ SignedCms innerCms = new SignedCms();
+ innerCms.Decode(asn.RawData);
+ innerCms.CheckHash();
+ if (innerCms.SignerInfos.Count > 0) {
+ SignerInfo innerSignerInfo = innerCms.SignerInfos[0];
+ innerSignerInfo.CheckSignature(false);
+ }
+ }
+ }
+
+ //calculate the hash using the first signed info
+ var hashAlg = IncrementalHash.CreateHash(new HashAlgorithmName(si.DigestAlgorithm.FriendlyName.ToUpper()));
+ byte[] calculatedHash = CalculatePeHashStreaming(hashAlg);
+ string hash = BitConverter.ToString(calculatedHash).Replace("-", "");
+
+ string content = BitConverter.ToString(cms.ContentInfo.Content).Replace("-", "");
+ if (!content.Contains(hash)) {
+ throw new CryptographicException("The expected hash and the actual hash did not match!");
+ }
+ }
+ }
+ }
+
+ public byte[] CalculatePeHashStreaming(IncrementalHash alg) {
+ using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+ stream.Seek(ImportantHashPositions.Chunk1.Start, SeekOrigin.Begin);
+ alg.AppendData(reader.ReadBytes(ImportantHashPositions.Chunk1.Length));
+
+ stream.Seek(ImportantHashPositions.Chunk2.Start, SeekOrigin.Begin);
+ alg.AppendData(reader.ReadBytes(ImportantHashPositions.Chunk2.Length));
+
+ stream.Seek(ImportantHashPositions.Chunk3.Start, SeekOrigin.Begin);
+ alg.AppendData(reader.ReadBytes(ImportantHashPositions.Chunk3.Length));
+
+ int blockSize = 8192;
+ int read = 0;
+ byte[] buf = new byte[blockSize];
+
+ foreach (IMAGE_SECTION_HEADER h in ImportantHashPositions.SectionTableHeaders) {
+ stream.Seek(h.PointerToRawData, SeekOrigin.Begin);
+ if (h.SizeOfRawData <= blockSize) {
+ //just read the full block as one
+ alg.AppendData(reader.ReadBytes((int)h.SizeOfRawData));
+ } else {
+ long pos = stream.Position;
+ long end = h.PointerToRawData + h.SizeOfRawData - blockSize;
+ //process the data into blocks
+ while (pos < end) {
+ read = stream.Read(buf, 0, blockSize);
+ alg.AppendData(buf, 0, read);
+ pos += blockSize;
+ }
+
+ int remaining = (int)(end - pos + blockSize);
+ if (remaining > 0) {
+ read = stream.Read(buf, 0, remaining);
+ alg.AppendData(buf, 0, read);
+ }
+ }
+ }
+
+ /*
+ 14. Create a value called FILE_SIZE, which is not part of the signature. Set this value to the
+ image’s file size, acquired from the underlying file system. If FILE_SIZE is greater than
+ SUM_OF_BYTES_HASHED, the file contains extra data that must be added to the hash. This data
+ begins at the SUM_OF_BYTES_HASHED file offset, and its length is:
+ (File Size) – ((Size of AttributeCertificateTable) + SUM_OF_BYTES_HASHED)
+ Note: The size of Attribute Certificate Table is specified in the second ULONG value in the
+ Certificate Table entry (32 bit: offset 132, 64 bit: offset 148) in Optional Header Data
+ Directories.
+ */
+ long FILE_SIZE = new FileInfo(FilePath).Length;
+
+ long leftoverBytesToHash = FILE_SIZE - ImportantHashPositions.SumOfBytesHashed - ImportantHashPositions.CertificateTableSize;
+
+ if (leftoverBytesToHash > 0) {
+ //HashBlock(alg, reader, SUM_OF_BYTES_HASHED + certTableSize, FILE_SIZE);
+ stream.Seek(ImportantHashPositions.SumOfBytesHashed, SeekOrigin.Begin);
+ byte[] leftoverBytes = reader.ReadBytes((int)leftoverBytesToHash);
+ alg.AppendData(leftoverBytes);
+ } else {
+ //no more bytes to hash...
+ }
+ //alg.TransformFinalBlock(new byte[0], 0, 0);
+
+ byte[] result = alg.GetHashAndReset();
+
+ return result;
+ }
+ }
+
+ public class HashPositions {
+ internal HashPositions() {
+ Chunk1 = new Range();
+ Chunk2 = new Range();
+ Chunk3 = new Range();
+ SectionTableHeaders = new List();
+ }
+ /*
+ * These functions are all based from the document linked to from the bottom of:
+ * https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-standard-fields-image-only
+ *
+ * Link to the document:
+ * https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
+ *
+ * Relevant section copied from that document:
+ * To calculate the hash value:
+ 1. Load the image header into memory.
+ 2. Initialize a hash algorithm context.
+ 3. Hash the image header from its base to immediately before the start of the
+ checksum address, as specified in Optional Header Windows-Specific Fields.
+ 4. Skip over the checksum, which is a 4-byte field.
+ 5. Hash everything from the end of the checksum field to immediately before the start of
+ the Certificate Table entry, as specified in Optional Header Data Directories.
+ 6. Get the Attribute Certificate Table address and size from the Certificate Table entry.
+ For details, see section 5.7 of the PE/COFF specification.
+ 7. Exclude the Certificate Table entry from the calculation and hash everything from the
+ end of the Certificate Table entry to the end of image header, including Section Table
+ (headers).The Certificate Table entry is 8 bytes long, as specified in Optional Header
+ Data Directories.
+ 8. Create a counter called SUM_OF_BYTES_HASHED, which is not part of the signature. Set
+ this counter to the SizeOfHeaders field, as specified in Optional Header Windows-Specific
+ Field.
+ 9. Build a temporary table of pointers to all of the section headers in the image. The
+ NumberOfSections field of COFF File Header indicates how big the table should be. Do not
+ include any section headers in the table whose SizeOfRawData field is zero.
+ 10. Using the PointerToRawData field (offset 20) in the referenced SectionHeader structure as
+ a key, arrange the table's elements in ascending order. In other words, sort the section
+ headers in ascending order according to the disk-file offset of the sections.
+ 11. Walk through the sorted table, load the corresponding section into memory, and hash the entire
+ section. Use the SizeOfRawData field in the SectionHeader structure to determine the amount
+ of data to hash.
+ 12. Add the section’s SizeOfRawData value to SUM_OF_BYTES_HASHED.
+ 13. Repeat steps 11 and 12 for all of the sections in the sorted table.
+ 14. Create a value called FILE_SIZE, which is not part of the signature. Set this value to the
+ image’s file size, acquired from the underlying file system. If FILE_SIZE is greater than
+ SUM_OF_BYTES_HASHED, the file contains extra data that must be added to the hash. This data
+ begins at the SUM_OF_BYTES_HASHED file offset, and its length is:
+ (File Size) – ((Size of AttributeCertificateTable) + SUM_OF_BYTES_HASHED)
+ Note: The size of Attribute Certificate Table is specified in the second ULONG value in the
+ Certificate Table entry (32 bit: offset 132, 64 bit: offset 148) in Optional Header Data
+ Directories.
+ 15. Finalize the hash algorithm context.
+ Note: This procedure uses offset values from the PE/COFF specification, version 8.1 .
+ For authoritative offset values, refer to the most recent version of the PE/COFF specification.
+ */
+
+ public List SectionTableHeaders { get; private set; }
+
+ ///
+ /// Chunk1 Start will set the position in the file which the hashing of the file should begin from
+ /// This is always the start of the file and thus is hardcoded to 0 and takes no parameters
+ ///
+ /// Chunk1 End is defined to be: "immediately before the start of the checksum address"
+ ///
+ /// Relevant step:
+ /// 3. Hash the image header from its base to immediately before the start of the
+ /// checksum address, as specified in Optional Header Windows-Specific Fields.
+ ///
+ public Range Chunk1 { get; private set; }
+
+ ///
+ /// Chunk2 Start is defined to be: "end of the checksum field"
+ /// Chunk2 End is defined to be: "immediately before the start of the Certificate Table entry"
+ ///
+ /// Relevant step:
+ /// 5. Hash everything from the end of the checksum field to immediately before the start of
+ /// the Certificate Table entry, as specified in Optional Header Data Directories.
+ ///
+ public Range Chunk2 { get; private set; }
+
+ ///
+ /// Chunk3 Start is defined to be: "the end of the Certificate Table entry"
+ /// Chunk3 End is defined to be: "the end of image header"
+ /// When testing/developing this solution - this was found to be the position specified by
+ /// the SizeOfHeaders field
+ ///
+ /// Relevant step:
+ /// 7. Exclude the Certificate Table entry from the calculation and hash everything from the
+ /// end of the Certificate Table entry to the end of image header, including Section Table
+ /// (headers).The Certificate Table entry is 8 bytes long, as specified in Optional Header
+ /// Data Directories.
+ ///
+ public Range Chunk3 { get; private set; }
+
+ public uint SizeOfHeaders { get; private set; }
+ public uint SumOfBytesHashed { get; private set; }
+ public long CertificateTableStart { get; private set; }
+ public long CertificateTableSize { get; private set; }
+
+ internal bool reorderNeeded = false;
+ private uint lastAddress = 0;
+ public void AddSectionTableHeader(IMAGE_SECTION_HEADER sectionTableHeader) {
+
+ if (sectionTableHeader.SizeOfRawData > 0) {
+ SectionTableHeaders.Add(sectionTableHeader);
+ }
+
+ if (lastAddress < sectionTableHeader.PointerToRawData) {
+ //good - it's in order...
+ } else {
+ reorderNeeded = true;
+ }
+ lastAddress = sectionTableHeader.PointerToRawData;
+ SumOfBytesHashed += sectionTableHeader.SizeOfRawData;
+ }
+
+ public void SetStartCoffHeader(uint peHeaderStart) {
+ Chunk1.Start = 0;
+ uint checksumStart = peHeaderStart + 88; //88 is the size of the COFF Header (24) + Standard Headers + Windows-Specific Fields up to checksum (offset 64)
+ Chunk1.End = checksumStart;
+ Chunk2.Start = checksumStart + LengthOfChecksum;
+
+ //and the four tables before the Certificate Table
+ //(ExportTable, ImportTable, ResourceTable, ExceptionTable)
+ uint certHeaderTableOffset = checksumStart + 64;
+
+ Chunk2.End = certHeaderTableOffset;
+ Chunk3.Start = certHeaderTableOffset + LenghtCertificateTable;
+ }
+
+ public void SetCertificateDetails(PeType type, uint sizeOfHeaders, uint certificateTableStart,
+ uint certificateTableSize) {
+ if (type == PeType.Pe32Plus) {
+ uint winSpecificExtraBytes = 16; //need to account for the extra bytes in the Windows-Specific Fields (each field has 4 extra bytes)
+ Chunk2.End += winSpecificExtraBytes;
+ Chunk3.Start += winSpecificExtraBytes;
+ }
+
+ Chunk3.End = sizeOfHeaders;
+ SizeOfHeaders = sizeOfHeaders;
+ SumOfBytesHashed = sizeOfHeaders;
+ CertificateTableStart = certificateTableStart;
+ CertificateTableSize = certificateTableSize;
+ }
+ }
+
+ public class Range {
+ public long Start { get; internal set; }
+ public long End { get; internal set; }
+
+ public int Length => (int)(End - Start);
+ }
+ }
+
+ public enum PeType {
+ Pe32,
+ Pe32Plus
+ }
+}
diff --git a/ZitiUpdateService/checkers/PeFile/StructHelper.cs b/ZitiUpdateService/checkers/PeFile/StructHelper.cs
new file mode 100644
index 00000000..8e655822
--- /dev/null
+++ b/ZitiUpdateService/checkers/PeFile/StructHelper.cs
@@ -0,0 +1,17 @@
+using System.Runtime.InteropServices;
+
+namespace ZitiUpdateService.Checkers.PeFile {
+ public static class StructHelper {
+
+ public static T FromBytes(byte[] bytes) {
+ //byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
+
+ // Pin the managed memory while, copy it out the data, then unpin it
+ GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
+ T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
+ handle.Free();
+
+ return theStructure;
+ }
+ }
+}
diff --git a/ZitiUpdateService/checkers/UpdateCheckers.cs b/ZitiUpdateService/checkers/UpdateCheckers.cs
index 582a15d8..374f1113 100644
--- a/ZitiUpdateService/checkers/UpdateCheckers.cs
+++ b/ZitiUpdateService/checkers/UpdateCheckers.cs
@@ -3,7 +3,7 @@ using System.IO;
using NLog;
-namespace ZitiUpdateService.checkers {
+namespace ZitiUpdateService.Checkers {
abstract class UpdateCheck {
public abstract int IsUpdateAvailable(Version current);
diff --git a/ZitiUpdateService/packages.config b/ZitiUpdateService/packages.config
index 2acb7a14..28608793 100644
--- a/ZitiUpdateService/packages.config
+++ b/ZitiUpdateService/packages.config
@@ -5,4 +5,5 @@
-
+
+
\ No newline at end of file
From 778ca8d54cb903439024cf21420b15c8bbb7edc2 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Fri, 28 May 2021 18:18:20 -0400
Subject: [PATCH 02/19] add openziti.rsa.root.signing.ca.pem as a resource
---
ZitiUpdateService/Properties/AssemblyInfo.cs | 4 ++--
ZitiUpdateService/ZitiUpdateService.csproj | 3 ++-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs
index 03a5efb4..c384a42b 100644
--- a/ZitiUpdateService/Properties/AssemblyInfo.cs
+++ b/ZitiUpdateService/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyFileVersion("1.9.6.0")]
+[assembly: AssemblyVersion("1.9.4.0")]
+[assembly: AssemblyFileVersion("1.9.4.0")]
diff --git a/ZitiUpdateService/ZitiUpdateService.csproj b/ZitiUpdateService/ZitiUpdateService.csproj
index 6f14703f..59e18a2a 100644
--- a/ZitiUpdateService/ZitiUpdateService.csproj
+++ b/ZitiUpdateService/ZitiUpdateService.csproj
@@ -13,6 +13,7 @@
true
true
false
+
publish\
true
Disk
@@ -28,7 +29,6 @@
false
true
true
-
x64
@@ -143,6 +143,7 @@
Always
+
Always
From a62f3701f71292213951524c4564a7eb45fd5372 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 10:06:25 -0400
Subject: [PATCH 03/19] checkpoint commit
---
ZitiUpdateService/App.config | 20 +-
ZitiUpdateService/UpdateService.cs | 17 +-
ZitiUpdateService/ZitiUpdateService.csproj | 16 +-
.../checkers/PeFile/SignedFileValidator.cs | 316 +++++++++++++++++-
.../checkers/PeFile/StructHelper.cs | 2 -
.../checkers/PeFile/Win32Crypto.cs | 249 ++++++++++++++
.../PeFile/openziti.rootCA.rsa.pem.txt | 33 ++
ZitiUpdateService/packages.config | 4 +
service/cziti/dns-proxy.go | 3 +
9 files changed, 635 insertions(+), 25 deletions(-)
create mode 100644 ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
create mode 100644 ZitiUpdateService/checkers/PeFile/openziti.rootCA.rsa.pem.txt
diff --git a/ZitiUpdateService/App.config b/ZitiUpdateService/App.config
index df91ae79..e2c58379 100644
--- a/ZitiUpdateService/App.config
+++ b/ZitiUpdateService/App.config
@@ -1,4 +1,4 @@
-
+
-
+
-
-
-
+
+
+
-
+
-
+
-
+
-
-
+
+
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index 59f7b246..418d8527 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -609,7 +609,7 @@ namespace ZitiUpdateService {
inUpdateCheck = true; //simple semaphore
try {
Logger.Debug("checking for update");
-
+ /*
int avail = check.IsUpdateAvailable(assemblyVersion);
if (avail >= 0) {
Logger.Debug("update check complete. no update available");
@@ -642,6 +642,21 @@ namespace ZitiUpdateService {
}
Logger.Debug("downloaded file hash was correct. update can continue.");
+ */
+
+
+
+
+
+ string fileDestination = @"C:\temp\signingtest\a\zz.exe";
+
+
+
+
+
+
+
+
new SignedFileValidator(fileDestination).Verify();
// check digital signature
diff --git a/ZitiUpdateService/ZitiUpdateService.csproj b/ZitiUpdateService/ZitiUpdateService.csproj
index 59e18a2a..78d8eab1 100644
--- a/ZitiUpdateService/ZitiUpdateService.csproj
+++ b/ZitiUpdateService/ZitiUpdateService.csproj
@@ -98,6 +98,16 @@
..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll
+
+ ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
+
@@ -105,6 +115,9 @@
+
+ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
+
@@ -120,6 +133,7 @@
+
Component
@@ -143,7 +157,6 @@
Always
-
Always
@@ -158,6 +171,7 @@
+
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 8691f8f6..351d98d3 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -1,14 +1,22 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Net.Http;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using NLog;
+using VerifyingFiles.PInvoke;
namespace ZitiUpdateService.Checkers.PeFile {
public class SignedFileValidator {
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
public const int LengthOfChecksum = 4; //the checksum is 4 bytes
- public const int LenghtCertificateTable = 8; //the Certificate Table is 8 bytes
+ public const int LengthCertificateTable = 8; //the Certificate Table is 8 bytes
public HashPositions ImportantHashPositions { get; private set; }
public string FilePath { get; private set; }
@@ -16,7 +24,11 @@ namespace ZitiUpdateService.Checkers.PeFile {
public IMAGE_FILE_HEADER CoffHeader { get; private set; }
public IMAGE_OPTIONAL_HEADER32 StandardFieldsPe32 { get; private set; }
public IMAGE_OPTIONAL_HEADER64 StandardFieldsPe32Plus { get; private set; }
+
+ private readonly X509Certificate2 expectedRootCa = null;
+
public SignedFileValidator(string pathToFile) {
+ expectedRootCa = certFromResource("ZitiUpdateService.checkers.PeFile.openziti.rootCA.rsa.pem.txt");
FilePath = pathToFile;
ImportantHashPositions = new HashPositions();
@@ -26,6 +38,16 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
}
+ private X509Certificate2 certFromResource(string resourceName) {
+ var assembly = this.GetType().Assembly;
+ using (Stream stream = assembly.GetManifestResourceStream(resourceName))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+ byte[] bytes = new byte[stream.Length];
+ stream.Read(bytes, 0, bytes.Length);
+ return new X509Certificate2(bytes);
+ }
+ }
+
// ReSharper disable once InconsistentNaming
private void parse() {
using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
@@ -71,8 +93,76 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
}
+ public List ExtractVerifiedSignatures() {
+ List list = new List();
+ using (FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+ //verify all the embedded signatures
+ stream.Seek(this.ImportantHashPositions.CertificateTableStart, SeekOrigin.Begin);
+ int readCertLen = reader.ReadInt32();
+ int readRevision = reader.ReadInt16();
+ int readCertType = reader.ReadInt16();
+ byte[] pkcs7 = reader.ReadBytes(readCertLen);
+
+ SignedCms cms = new SignedCms();
+ cms.Decode(pkcs7);
+ cms.CheckHash();
+
+ //shout out to Scott MG: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/655f5c27-b049-4275-a8b3-cc1c0be2b4f2/retrieve-certificate-info-for-dualsigned-sha1sha256
+ //for indicating that the unsigned attributes contain the other SignerInfos
+ foreach (var cmsSi in cms.SignerInfos) {
+ cmsSi.CheckSignature(true);
+ if (VerifyTrust(expectedRootCa, cmsSi.Certificate).Result) {
+ VerifyFileHash(cms, cmsSi);
+ list.Add(cms);
+ }
+ if (cmsSi.UnsignedAttributes.Count > 0) {
+ foreach (var unsignedAttr in cmsSi.UnsignedAttributes) {
+ foreach (AsnEncodedData asn in unsignedAttr.Values) {
+ SignedCms innerCms = new SignedCms();
+ innerCms.Decode(asn.RawData);
+ innerCms.CheckHash();
+ if (innerCms.SignerInfos.Count > 0) {
+ SignerInfo innerSignerInfo = innerCms.SignerInfos[0];
+ try {
+ innerSignerInfo.CheckSignature(false);
+ }
+ catch (CryptographicException ce) {
+ if (innerSignerInfo.Certificate.Thumbprint == "39636E9F5E80308DE370C914CE8112876ECF4E0C") {
+ //special handling for the known 'old' NetFoundry signing certificate, now expired...
+ //TODO: remove this code after 2021
+ //just allow this one error
+ Logger.Warn("Ignoring timestamp validity issue for the existing code signing certificate. Subject: {0}, Thumbprint: {1}", innerSignerInfo.Certificate.Subject, innerSignerInfo.Certificate.Thumbprint);
+ } else {
+ throw;
+ }
+ }
+
+ if (VerifyTrust(expectedRootCa, innerSignerInfo.Certificate).Result) {
+ VerifyFileHash(innerCms, innerSignerInfo);
+ list.Add(innerCms);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return list;
+ }
+
public void Verify() {
- using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
+ List list = ExtractVerifiedSignatures();
+ foreach (SignedCms cms in list) {
+ //ignore entries with a version of 3 since this indicates a timestamp signature and not one we
+ Console.WriteLine(cms.Certificates);
+ }
+ }
+
+ /*
+ public void Verify() {
+ using (FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
using (BinaryReader reader = new BinaryReader(stream)) {
//verify all the embedded signatures
stream.Seek(this.ImportantHashPositions.CertificateTableStart, SeekOrigin.Begin);
@@ -89,6 +179,10 @@ namespace ZitiUpdateService.Checkers.PeFile {
if (cms.SignerInfos.Count > 0) {
SignerInfo si = cms.SignerInfos[0];
si.CheckSignature(true);
+ if (VerifyTrust(expectedRootCa, si.Certificate).Result) {
+ VerifyFileHash(cms, si);
+ return; //success!
+ }
if (cms.SignerInfos[0] != null && cms.SignerInfos[0].UnsignedAttributes.Count > 0) {
foreach (AsnEncodedData asn in cms.SignerInfos[0].UnsignedAttributes[0].Values) {
SignedCms innerCms = new SignedCms();
@@ -97,23 +191,108 @@ namespace ZitiUpdateService.Checkers.PeFile {
if (innerCms.SignerInfos.Count > 0) {
SignerInfo innerSignerInfo = innerCms.SignerInfos[0];
innerSignerInfo.CheckSignature(false);
+ if (VerifyTrust(expectedRootCa, innerSignerInfo.Certificate).Result) {
+ VerifyFileHash(innerCms, innerSignerInfo);
+ return; //success!
+ }
}
}
}
+ }
- //calculate the hash using the first signed info
- var hashAlg = IncrementalHash.CreateHash(new HashAlgorithmName(si.DigestAlgorithm.FriendlyName.ToUpper()));
- byte[] calculatedHash = CalculatePeHashStreaming(hashAlg);
- string hash = BitConverter.ToString(calculatedHash).Replace("-", "");
+ throw new CryptographicException("No signing certificates found which meet the expected criteria");
+ }
+ }
+ */
+ public void VerifyFileHash(SignedCms cms, SignerInfo signerInfo) {
+ if (!signerInfo.Certificate.Subject.ToLower().Contains("netfoundry")) {
+ //just eject - no need to check this...
+ Logger.Debug("Not verifying certificate as it is not a NetFoundry signing certificate: {0}", signerInfo.Certificate.Subject);
+ return;
+ }
+ //calculate the hash using the first signed info
+ var hashAlg = IncrementalHash.CreateHash(new HashAlgorithmName(signerInfo.DigestAlgorithm.FriendlyName.ToUpper()));
+ byte[] calculatedHash = CalculatePeHashStreaming(hashAlg);
+ string hash = BitConverter.ToString(calculatedHash).Replace("-", "");
- string content = BitConverter.ToString(cms.ContentInfo.Content).Replace("-", "");
- if (!content.Contains(hash)) {
- throw new CryptographicException("The expected hash and the actual hash did not match!");
+ string content = BitConverter.ToString(cms.ContentInfo.Content).Replace("-", "");
+ if (!content.Contains(hash)) {
+ throw new CryptographicException("The expected hash and the actual hash did not match!");
+ }
+ }
+
+ public async static Task VerifyTrust(X509Certificate2 trustedRootCertificateAuthority, X509Certificate2 certificate) {
+
+ X509Store store = new X509Store("LocalMachine", StoreLocation.LocalMachine);
+ store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
+
+ X509Chain chain = new X509Chain();
+ chain.ChainPolicy.ExtraStore.Add(trustedRootCertificateAuthority);
+ chain.ChainPolicy.ExtraStore.AddRange(store.Certificates);
+ chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
+ chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
+ chain.Build(new X509Certificate2(certificate));
+ List exceptions = new List();
+ foreach (X509ChainStatus status in chain.ChainStatus) {
+ if (status.Status == X509ChainStatusFlags.NoError || status.Status == X509ChainStatusFlags.UntrustedRoot || status.Status == X509ChainStatusFlags.NotTimeValid) {
+ //X509ChainStatusFlags.UntrustedRoot simply means it was not found in the computer/user's trust store.... that's fine...
+ //X509ChainStatusFlags.NotTimeValid means the certificate has expired - we're allowing this for now (summer 2021) to allow older clients to update
+ } else {
+ exceptions.Add(new CryptographicException("Could not verify trust: " + status.StatusInformation));
+ }
+ }
+
+ //final check - make sure the last certificate matches the expected thumbprint
+ if (chain.ChainElements[chain.ChainElements.Count - 1].Certificate.Thumbprint != trustedRootCertificateAuthority.Thumbprint) {
+ exceptions.Add(new Exception("Could not verify trust. The expected thumbprint was not found!"));
+ }
+
+ bool crlFailure = false;
+ foreach (var e in certificate.Extensions) {
+ if (e.Oid.Value == "2.5.29.31") { //2.5.29.31 == CRL Distribution Points
+ try {
+ CrlDistributionPointParser t = new CrlDistributionPointParser(e.RawData);
+
+ if (t != null) {
+ foreach (string url in t.urls) {
+ try {
+ //good - things are going the way we want... keep going
+ //fetch the CRL from the url provided and parse it...
+ byte[] crlBytes = await new HttpClient().GetByteArrayAsync(url);
+
+ if (crlBytes != null && crlBytes.Length > 0) {
+ //fetch the crl
+ Win32Crypto.CrlInfo info = Win32Crypto.FromBlob(crlBytes);
+ if (info.RevokedSerialNumbers.Contains(certificate.SerialNumber)) {
+ exceptions.Add(new CryptographicException("Serial number " + certificate.SerialNumber + " has been revoked."));
+ crlFailure = true;
+ }
+ } else {
+ exceptions.Add(new CryptographicException("Could not retrieve revocation list from " + url + "- cannot verify trust"));
+ crlFailure = true;
+ }
+ }
+ catch (Exception innerException) {
+ exceptions.Add(new CryptographicException("crl at " + url + " could not be used", innerException));
+ crlFailure = true;
+ }
+ }
+ }
+ }
+ catch (Exception ex) {
+ exceptions.Add(ex);
+ break;
}
}
}
+
+ if (crlFailure) {
+ throw new AggregateException(exceptions);
+ }
+
+ return true;
}
-
+
public byte[] CalculatePeHashStreaming(IncrementalHash alg) {
using (FileStream stream = new FileStream(FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (BinaryReader reader = new BinaryReader(stream)) {
@@ -310,7 +489,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
uint certHeaderTableOffset = checksumStart + 64;
Chunk2.End = certHeaderTableOffset;
- Chunk3.Start = certHeaderTableOffset + LenghtCertificateTable;
+ Chunk3.Start = certHeaderTableOffset + LengthCertificateTable;
}
public void SetCertificateDetails(PeType type, uint sizeOfHeaders, uint certificateTableStart,
@@ -341,4 +520,119 @@ namespace ZitiUpdateService.Checkers.PeFile {
Pe32,
Pe32Plus
}
+
+ public class CRLDistributionPointsParser {
+ public static List GetCrlUrls(BinaryReader asn1Data) {
+ //read the first byte - make sure it's marker 0x30 for SEQUENCE
+ byte first = asn1Data.ReadByte();
+ if (first != 0x30) {
+ throw new CryptographicException("Could not parse CRL Distribution Points. First byte not asn marker");
+ }
+
+ if (first > 127) {
+ //means there's more bytes to read that control the overall length of the next section
+ }
+ List rtn = new List();
+
+ return rtn;
+ }
+
+ private static void readType(MemoryStream asn1Data) {
+
+ }
+
+ private static void readLen(byte lenByte, MemoryStream asn1Data) {
+
+ }
+ /*
+ internal static CrlDistributionPointParser ParseTags(BinaryReader asn1Data, int asn1DataLen) {
+
+ CrlDistributionPointParser tag = new CrlDistributionPointParser(asn1Data, asn1DataLen);
+
+ return tag;
+ }*/
+ }
+
+ internal class CrlDistributionPointParser {
+ internal int offset;
+ internal int length;
+ internal List tags = new List();
+ private CrlDistributionPointParser parent = null;
+ private AsnTagType type = AsnTagType.NONE;
+ internal List urls = new List();
+ private int consumedBytes = 0;
+
+ internal CrlDistributionPointParser(byte[] asn1Data) : this(new MemoryStream(asn1Data)) {
+
+ }
+
+ internal CrlDistributionPointParser(MemoryStream asn1Data) : this(null, asn1Data/*new BinaryReader(asn1Data)*/, 0) {
+
+ }
+
+ internal CrlDistributionPointParser(CrlDistributionPointParser parent, MemoryStream memoryStream, /*BinaryReader asn1Reader,*/ int offset) {
+ BinaryReader asn1Reader = new BinaryReader(memoryStream);
+ this.offset = offset;
+ type = readTag(asn1Reader);
+ length = readTagLen(asn1Reader);
+ this.parent = parent;
+ int headerBytes = consumedBytes;
+ while (this.consumedBytes < length + headerBytes) {
+ switch (type) {
+ case AsnTagType.SEQUENCE:
+ case AsnTagType.ARRAY_ELEMENT:
+ var t = new CrlDistributionPointParser(this, memoryStream, (int) memoryStream.Position);
+ consumedBytes += t.consumedBytes;
+ tags.Add(t);
+ this.urls.AddRange(t.urls);
+ break;
+ case AsnTagType.STRING:
+ consumedBytes += length;
+ urls.Add(System.Text.Encoding.UTF8.GetString(asn1Reader.ReadBytes(length)));
+ break;
+ }
+ }
+ }
+
+ internal AsnTagType readTag(BinaryReader asn1Data) {
+ byte tagByte = asn1Data.ReadByte();
+ if (tagByte != 0x30 && tagByte != 0xA0 && tagByte != 0x86) {
+ throw new CryptographicException("Could not parse CRL Distribution Points. First byte not asn SEQUENCE|ARRAY|STRING marker");
+ }
+
+ consumedBytes++;
+ if (tagByte == 0x30) return AsnTagType.SEQUENCE;
+ if (tagByte == 0xA0) return AsnTagType.ARRAY_ELEMENT;
+ if (tagByte == 0x86) return AsnTagType.STRING;
+ return AsnTagType.NONE;
+ }
+
+ internal int readTagLen(BinaryReader asn1Data) {
+ int tagLen = asn1Data.ReadByte();
+ consumedBytes++;
+ if (tagLen > 128) {
+ //means there's more bytes to read that control the overall length of the next section
+ int moreBytes = tagLen - 128;
+ byte[] lenBytes = new byte[4];
+ byte[] d = asn1Data.ReadBytes(moreBytes);
+
+ int pos = 0;
+ for (int i = d.Length - 1; i >= 0; i--) {
+ lenBytes[pos++] = d[i];
+ }
+
+ tagLen = BitConverter.ToInt32(lenBytes, 0);
+ consumedBytes += moreBytes;
+ }
+
+ return tagLen;
+ }
+ }
+
+ internal enum AsnTagType {
+ SEQUENCE = 0x30,
+ ARRAY_ELEMENT = 0xA0,
+ STRING = 0x86,
+ NONE = 0,
+ }
}
diff --git a/ZitiUpdateService/checkers/PeFile/StructHelper.cs b/ZitiUpdateService/checkers/PeFile/StructHelper.cs
index 8e655822..60670764 100644
--- a/ZitiUpdateService/checkers/PeFile/StructHelper.cs
+++ b/ZitiUpdateService/checkers/PeFile/StructHelper.cs
@@ -4,8 +4,6 @@ namespace ZitiUpdateService.Checkers.PeFile {
public static class StructHelper {
public static T FromBytes(byte[] bytes) {
- //byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
-
// Pin the managed memory while, copy it out the data, then unpin it
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
diff --git a/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs b/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
new file mode 100644
index 00000000..a515baf6
--- /dev/null
+++ b/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace VerifyingFiles.PInvoke {
+ public static class Win32Crypto {
+ //based on https://docs.microsoft.com/en-us/archive/blogs/alejacma/how-to-get-information-from-a-crl-net
+
+ #region APIs
+ [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern Boolean CryptQueryObject(
+ Int32 dwObjectType,
+ [MarshalAs(UnmanagedType.LPWStr)] String pvObject,
+ Int32 dwExpectedContentTypeFlags,
+ Int32 dwExpectedFormatTypeFlags,
+ Int32 dwFlags,
+ IntPtr pdwMsgAndCertEncodingType,
+ IntPtr pdwContentType,
+ IntPtr pdwFormatType,
+ IntPtr phCertStore,
+ IntPtr phMsg,
+ ref IntPtr ppvContext
+ );
+ [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern Boolean CryptQueryObject2(
+ Int32 dwObjectType,
+ IntPtr pvObject,
+ Int32 dwExpectedContentTypeFlags,
+ Int32 dwExpectedFormatTypeFlags,
+ Int32 dwFlags,
+ IntPtr pdwMsgAndCertEncodingType,
+ IntPtr pdwContentType,
+ IntPtr pdwFormatType,
+ ref IntPtr phCertStore,
+ IntPtr phMsg,
+ ref IntPtr ppvContext
+ );
+
+ [DllImport("CRYPT32.DLL", EntryPoint = "CertFreeCRLContext", SetLastError = true)]
+ public static extern Boolean CertFreeCRLContext(
+ IntPtr pCrlContext
+ );
+
+ [DllImport("CRYPT32.DLL", EntryPoint = "CertNameToStr", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern Int32 CertNameToStr(
+ Int32 dwCertEncodingType,
+ ref CRYPTOAPI_BLOB pName,
+ Int32 dwStrType,
+ StringBuilder psz,
+ Int32 csz
+ );
+
+ [DllImport("CRYPT32.DLL", EntryPoint = "CertFindExtension", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr CertFindExtension(
+ [MarshalAs(UnmanagedType.LPStr)] String pszObjId,
+ Int32 cExtensions,
+ IntPtr rgExtensions
+ );
+
+ [DllImport("CRYPT32.DLL", EntryPoint = "CryptFormatObject", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern Boolean CryptFormatObject(
+ Int32 dwCertEncodingType,
+ Int32 dwFormatType,
+ Int32 dwFormatStrType,
+ IntPtr pFormatStruct,
+ [MarshalAs(UnmanagedType.LPStr)] String lpszStructType,
+ IntPtr pbEncoded,
+ Int32 cbEncoded,
+ StringBuilder pbFormat,
+ ref Int32 pcbFormat
+ );
+
+ #endregion APIs
+
+ #region Structs
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRL_CONTEXT {
+ public Int32 dwCertEncodingType;
+ public IntPtr pbCrlEncoded;
+ public Int32 cbCrlEncoded;
+ public IntPtr pCrlInfo;
+ public IntPtr hCertStore;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRL_INFO {
+ public Int32 dwVersion;
+ public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
+ public CRYPTOAPI_BLOB Issuer;
+ public FILETIME ThisUpdate;
+ public FILETIME NextUpdate;
+ public Int32 cCRLEntry;
+ public IntPtr rgCRLEntry;
+ public Int32 cExtension;
+ public IntPtr rgExtension;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPT_ALGORITHM_IDENTIFIER {
+ [MarshalAs(UnmanagedType.LPStr)] public String pszObjId;
+ public CRYPTOAPI_BLOB Parameters;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRYPTOAPI_BLOB {
+ public Int32 cbData;
+ public IntPtr pbData;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct FILETIME {
+ public Int32 dwLowDateTime;
+ public Int32 dwHighDateTime;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CRL_ENTRY {
+ public CRYPTOAPI_BLOB SerialNumber;
+ public FILETIME RevocationDate;
+ public Int32 cExtension;
+ public IntPtr rgExtension;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CERT_EXTENSION {
+ [MarshalAs(UnmanagedType.LPStr)] public String pszObjId;
+ public Boolean fCritical;
+ public CRYPTOAPI_BLOB Value;
+ }
+
+ #endregion Structs
+
+ #region Consts
+
+ public const Int32 CERT_QUERY_OBJECT_BLOB = 0x00000002;
+ public const Int32 CERT_QUERY_CONTENT_CRL = 3;
+ public const Int32 CERT_QUERY_CONTENT_FLAG_CRL = 1 << CERT_QUERY_CONTENT_CRL;
+ public const Int32 CERT_QUERY_FORMAT_BINARY = 1;
+ public const Int32 CERT_QUERY_FORMAT_BASE64_ENCODED = 2;
+ public const Int32 CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3;
+ public const Int32 CERT_QUERY_FORMAT_FLAG_BINARY = 1 << CERT_QUERY_FORMAT_BINARY;
+ public const Int32 CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED;
+ public const Int32 CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
+ public const Int32 CERT_QUERY_FORMAT_FLAG_ALL = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED;
+
+ public const Int32 X509_ASN_ENCODING = 0x00000001;
+ public const Int32 PKCS_7_ASN_ENCODING = 0x00010000;
+
+ public const Int32 X509_NAME = 7;
+
+ public const Int32 CERT_SIMPLE_NAME_STR = 1;
+ public const Int32 CERT_OID_NAME_STR = 2;
+ public const Int32 CERT_X500_NAME_STR = 3;
+
+ public const String szOID_CRL_REASON_CODE = "2.5.29.21";
+
+ #endregion
+
+ private static List GetRevokedGetSerialNumbers(CRL_INFO stCrlInfo) {
+ List rtn = new List();
+ var rgCrlEntry = stCrlInfo.rgCRLEntry;
+
+ for (var i = 0; i < stCrlInfo.cCRLEntry; i++) {
+ var serial = string.Empty;
+ var stCrlEntry = (CRL_ENTRY)Marshal.PtrToStructure(rgCrlEntry, typeof(CRL_ENTRY));
+
+ IntPtr pByte = stCrlEntry.SerialNumber.pbData;
+ for (var j = 0; j < stCrlEntry.SerialNumber.cbData; j++) {
+ Byte bByte = Marshal.ReadByte(pByte);
+ serial = bByte.ToString("X").PadLeft(2, '0') + serial;
+ pByte = pByte + Marshal.SizeOf(typeof(byte));
+
+ }
+ rtn.Add(serial);
+ rgCrlEntry = rgCrlEntry + Marshal.SizeOf(typeof(CRL_ENTRY));
+ }
+
+ return rtn;
+ }
+
+ public static DateTime FileTimeToDateTime(FILETIME fileTime) {
+ DateTime dateTime;
+ IntPtr int64Ptr = Marshal.AllocHGlobal(sizeof(Int64));
+ try {
+ Marshal.StructureToPtr(fileTime, int64Ptr, true);
+ dateTime = DateTime.FromFileTime(Marshal.ReadInt64(int64Ptr));
+ } finally {
+ Marshal.FreeHGlobal(int64Ptr);
+ }
+
+ return dateTime;
+ }
+
+ public static CrlInfo FromBlob(byte[] CrlDERBytes) {
+
+ var phCertStore = IntPtr.Zero;
+ var pvContext = IntPtr.Zero;
+ var hCrlData = new GCHandle();
+ var hCryptBlob = new GCHandle();
+ try {
+ hCrlData = GCHandle.Alloc(CrlDERBytes, GCHandleType.Pinned);
+ CRYPTOAPI_BLOB stCryptBlob;
+ stCryptBlob.cbData = CrlDERBytes.Length;
+ stCryptBlob.pbData = hCrlData.AddrOfPinnedObject();
+ hCryptBlob = GCHandle.Alloc(stCryptBlob, GCHandleType.Pinned);
+
+ if (!CryptQueryObject2(
+ CERT_QUERY_OBJECT_BLOB,
+ hCryptBlob.AddrOfPinnedObject(),
+ CERT_QUERY_CONTENT_FLAG_CRL,
+ CERT_QUERY_FORMAT_FLAG_BINARY,
+ 0,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ ref phCertStore,
+ IntPtr.Zero,
+ ref pvContext
+ )) {
+ throw new Win32Exception(Marshal.GetLastWin32Error(), "CRL is Corrupted.");
+ }
+ var stCrlContext = (CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(CRL_CONTEXT));
+ var stCrlInfo = (CRL_INFO)Marshal.PtrToStructure(stCrlContext.pCrlInfo, typeof(CRL_INFO));
+
+ CrlInfo info = new CrlInfo();
+ info.validTo = FileTimeToDateTime(stCrlInfo.NextUpdate);
+ info.validFrom = FileTimeToDateTime(stCrlInfo.ThisUpdate);
+ info.RevokedSerialNumbers = GetRevokedGetSerialNumbers(stCrlInfo);
+
+ return info;
+ } finally {
+ if (hCrlData.IsAllocated) hCrlData.Free();
+ if (hCryptBlob.IsAllocated) hCryptBlob.Free();
+ if (!pvContext.Equals(IntPtr.Zero)) {
+ CertFreeCRLContext(pvContext);
+ }
+ }
+ }
+
+ public struct CrlInfo {
+ public DateTime validTo;
+ public DateTime validFrom;
+ public List RevokedSerialNumbers;
+ }
+ }
+}
diff --git a/ZitiUpdateService/checkers/PeFile/openziti.rootCA.rsa.pem.txt b/ZitiUpdateService/checkers/PeFile/openziti.rootCA.rsa.pem.txt
new file mode 100644
index 00000000..87464af1
--- /dev/null
+++ b/ZitiUpdateService/checkers/PeFile/openziti.rootCA.rsa.pem.txt
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFozCCA4ugAwIBAgIUdhfTn8Eu4pU39MIPpoerTLqbLRkwDQYJKoZIhvcNAQEN
+BQAwYTEYMBYGA1UEAwwPUm9vdCBTaWduaW5nIENBMRkwFwYDVQQKDBBvcGVueml0
+aS5vcmcgSW5jMRAwDgYDVQQLDAdhZHYtZGV2MQswCQYDVQQGEwJVUzELMAkGA1UE
+CAwCTkMwHhcNMjEwNjAyMTcyNDMzWhcNNDEwNjE3MTcyNDMzWjBhMRgwFgYDVQQD
+DA9Sb290IFNpZ25pbmcgQ0ExGTAXBgNVBAoMEG9wZW56aXRpLm9yZyBJbmMxEDAO
+BgNVBAsMB2Fkdi1kZXYxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOQzCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBALcLp/jh0zYqDQw6Gxzoxnib08QLwBo7
+AHLdJSOxdFy3K0a7xSEZjkhJgWQWw/c/HArw5PiHS4jdsh7o8mSJGLqBj+s/Gj4M
+tM4k3A5jJHcgAbDKPAaAZAXQ2aEDp8eA65S1mRqNnYHbmTm3Q3t3U7dqI1lISzjz
+k5jBQnXS3Qtlj2SyMXRYPpPJIQlXgZXdvLmL7wG1FpmCFBSEEdOVMIhEr5hJ/5rc
+HpTRSueLPpdJUSv3B3uuPdo5rI/pJJ6gAJUtmMw/G8CAlMwXlUbSLt5IvNriyjqT
+pisTjkQR0Vs8pvAN0CKfOqwoPWDwuJkump+LRTTQ0PLaNCnlU96mpoX9D7yhQAGP
+C5h0N0jPV2MpnEFNVPaGE43Wj1zejVP1S5Ep3i/Xu/aSUGmIK5MQ95z/J927LBKe
+AOyQDdQC0WkCBpCzpe0G9c+M0u7lYUHWXExWB22nQT2rM3aG5ZdOJRu42PXFNUr4
+bgkZq56PiCCgwDENOlln6/h8wD2a2o5n638BCwW3Qq4w8u2e7dKIAjNroQ053iyw
+ZmSIwImf9N+0631d8LDoVLllry+geP1bSlI1UCYcVjJWGSDwEmK9h+kwUsMX+yl7
+TAzgrnAkBS+C62sDvGHRjhp82IDklqsBQV7SsRG5ZqHAipbIa0NfCURsqmQ6iyNR
+a3/9oiE9ARdHAgMBAAGjUzBRMB0GA1UdDgQWBBS0v5OYBy16UEw7k7nMLg7Y3Fs7
+uDAfBgNVHSMEGDAWgBS0v5OYBy16UEw7k7nMLg7Y3Fs7uDAPBgNVHRMBAf8EBTAD
+AQH/MA0GCSqGSIb3DQEBDQUAA4ICAQBPtyCaKyk+WhXI1Gu83h6ePKuevwwnBygr
+xOEJM7b0kAxtcgK46B9wPgvLuUw1znmDzAuAqU52k00q1xLGZ+N5JNhlzzNWW0n2
+8Kj0gFLmu3tO7XXjQfQPKiZp/iiwOG9XPVVDTF2HVqkOsvdGYD2XH+wI4v/4m3wa
+xTvliEz9NCei7/NOhuTbJvbvcSmqAvs3+gH55bzBvvr+Hx/krx8HMcBikx92S5nF
+NKBkHIUQVqGoCHxGY/uM0xou5797faVEzLkaDle+oisMiy061pYI0bb9CRdHAU0r
+UoemoY3UOKlyK57wdXKRizDxmEyND2zxPYrktZu0SybjZmaFOCHLLp1WrcTlcp3C
+7Lsuj9Vzui2mjJuQzSTEyd1R04AT3xwb9slN+iHuN1dAGexVsENahW2q9ZAjEtbu
+E6B+gOrSJ7WaL8R7AAz/E3tfU2bYm99JoGCPjI2/kP7udw7EqvoKYfJO1gbRo45z
+37xJmDrxb2SJFEtn5mqPO63HjGXGiC6xI52Olmv4Csk3WOseO3j9/SwazDAMqZSh
+dY0BN0DADO8kiohyF+Cq7nPR/tX17DpQiWFgJ4xoYHRFYCyb6QZ5jOzMhrZJa7cM
+v7BIbBcUe1vcKJ+gD6dXMT77KakdkRSfuiuEAeh6GmjPC130ni1stn+chw0pymax
+ZSpzkClEkQ==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/ZitiUpdateService/packages.config b/ZitiUpdateService/packages.config
index 28608793..4e54d782 100644
--- a/ZitiUpdateService/packages.config
+++ b/ZitiUpdateService/packages.config
@@ -5,5 +5,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/service/cziti/dns-proxy.go b/service/cziti/dns-proxy.go
index 94b1002a..1e311972 100644
--- a/service/cziti/dns-proxy.go
+++ b/service/cziti/dns-proxy.go
@@ -354,6 +354,7 @@ outer:
for {
select {
case pr := <-proxiedRequests:
+ log.Warnf("i am in proxiedRequests")
id := (uint32(pr.req.Id) << 16) | uint32(pr.req.Question[0].Qtype)
reqs[id] = pr
b, _ := pr.req.Pack()
@@ -376,6 +377,7 @@ outer:
}
case rep := <-respChan:
+ log.Warnf("i am in respChan")
reply := dns.Msg{}
if err := reply.Unpack(rep); err == nil {
id := (uint32(reply.Id) << 16) | uint32(reply.Question[0].Qtype)
@@ -394,6 +396,7 @@ outer:
}
}
case <-time.After(time.Minute):
+ log.Warnf("i am in time.After")
// cleanup requests we didn't get answers for
now := time.Now()
for k, r := range reqs {
From 63142a1d8f46293fddc3f315fb64aa9dcc751a7f Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 14:15:51 -0400
Subject: [PATCH 04/19] next round of fixes - ready to push to beta and test
---
ZitiUpdateService/UpdateService.cs | 34 +------
.../checkers/PeFile/SignedFileValidator.cs | 92 ++++++++-----------
2 files changed, 41 insertions(+), 85 deletions(-)
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index 418d8527..e423071e 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -609,7 +609,7 @@ namespace ZitiUpdateService {
inUpdateCheck = true; //simple semaphore
try {
Logger.Debug("checking for update");
- /*
+
int avail = check.IsUpdateAvailable(assemblyVersion);
if (avail >= 0) {
Logger.Debug("update check complete. no update available");
@@ -642,40 +642,8 @@ namespace ZitiUpdateService {
}
Logger.Debug("downloaded file hash was correct. update can continue.");
- */
-
-
-
-
-
- string fileDestination = @"C:\temp\signingtest\a\zz.exe";
-
-
-
-
-
-
-
-
new SignedFileValidator(fileDestination).Verify();
- // check digital signature
- var signer = X509Certificate.CreateFromSignedFile(fileDestination);
- /* keep these commented out lines - just in case we need all the certs from the file use this
- var coll = new X509Certificate2Collection();
- coll.Import(filePath);
- */
-
- var subject = signer.Subject;
- if (!expected_subject.Contains(subject)) {
- Logger.Error("the file downloaded uses a subject that is unknown! the installation will not proceed. [subject:{0}]", subject);
- inUpdateCheck = false;
- return;
-
- } else {
- Logger.Info("the file downloaded uses a known subject. installation and can proceed. [subject:{0}]", subject);
- }
-
StopZiti();
StopUI().Wait();
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 351d98d3..56ef02c8 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -93,8 +93,18 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
}
- public List ExtractVerifiedSignatures() {
- List list = new List();
+ private void addCertToList(SignerInfo si, List list) {
+
+ X509Certificate2 cert = si.Certificate;
+ if (list.Find(x => x.Thumbprint == cert.Thumbprint) == null) {
+ list.Add(cert);
+ } else {
+ Logger.Debug("Certificate with Thumbprint {0} already in list. skipping.", cert.Thumbprint);
+ }
+ }
+
+ public List ExtractVerifiedSignatureCertificates() {
+ List list = new List();
using (FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
using (BinaryReader reader = new BinaryReader(stream)) {
//verify all the embedded signatures
@@ -114,7 +124,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
cmsSi.CheckSignature(true);
if (VerifyTrust(expectedRootCa, cmsSi.Certificate).Result) {
VerifyFileHash(cms, cmsSi);
- list.Add(cms);
+ addCertToList(cmsSi, list);
}
if (cmsSi.UnsignedAttributes.Count > 0) {
foreach (var unsignedAttr in cmsSi.UnsignedAttributes) {
@@ -134,13 +144,17 @@ namespace ZitiUpdateService.Checkers.PeFile {
//just allow this one error
Logger.Warn("Ignoring timestamp validity issue for the existing code signing certificate. Subject: {0}, Thumbprint: {1}", innerSignerInfo.Certificate.Subject, innerSignerInfo.Certificate.Thumbprint);
} else {
- throw;
+ if (IsCertificateOpenZitiVerifies(innerSignerInfo.Certificate)) {
+ Logger.Debug("Signature could not be verified. This is expected for the certificates issued by openziti/netfoundry.");
+ } else {
+ throw;
+ }
}
}
if (VerifyTrust(expectedRootCa, innerSignerInfo.Certificate).Result) {
VerifyFileHash(innerCms, innerSignerInfo);
- list.Add(innerCms);
+ addCertToList(innerSignerInfo, list);
}
}
}
@@ -152,64 +166,38 @@ namespace ZitiUpdateService.Checkers.PeFile {
return list;
}
- public void Verify() {
- List list = ExtractVerifiedSignatures();
- foreach (SignedCms cms in list) {
- //ignore entries with a version of 3 since this indicates a timestamp signature and not one we
- Console.WriteLine(cms.Certificates);
+ public bool IsCertificateOpenZitiVerifies(X509Certificate2 cert) {
+ bool yesOrNo = cert.Subject.ToLower().Contains("netfoundry") || cert.Subject.ToLower().Contains("openziti");
+ if (yesOrNo) {
+ Logger.Debug("Certificate is one openziti verifies: {0}", cert.Subject);
}
+ return yesOrNo;
}
- /*
public void Verify() {
- using (FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
- using (BinaryReader reader = new BinaryReader(stream)) {
- //verify all the embedded signatures
- stream.Seek(this.ImportantHashPositions.CertificateTableStart, SeekOrigin.Begin);
- int readCertLen = reader.ReadInt32();
- int readRevision = reader.ReadInt16();
- int readCertType = reader.ReadInt16();
- byte[] pkcs7 = reader.ReadBytes(readCertLen);
+ List list = ExtractVerifiedSignatureCertificates();
+ foreach (X509Certificate2 cert in list) {
+ if (IsCertificateOpenZitiVerifies(cert)) {
+ //verify this certificate was issued from the known CA
+ try {
+ VerifyTrust(expectedRootCa, cert);
- SignedCms cms = new SignedCms();
- cms.Decode(pkcs7);
- cms.CheckHash();
- //shout out to Scott MG: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/655f5c27-b049-4275-a8b3-cc1c0be2b4f2/retrieve-certificate-info-for-dualsigned-sha1sha256
- //for indicating that the unsigned attributes contain the other fingerprints
- if (cms.SignerInfos.Count > 0) {
- SignerInfo si = cms.SignerInfos[0];
- si.CheckSignature(true);
- if (VerifyTrust(expectedRootCa, si.Certificate).Result) {
- VerifyFileHash(cms, si);
- return; //success!
- }
- if (cms.SignerInfos[0] != null && cms.SignerInfos[0].UnsignedAttributes.Count > 0) {
- foreach (AsnEncodedData asn in cms.SignerInfos[0].UnsignedAttributes[0].Values) {
- SignedCms innerCms = new SignedCms();
- innerCms.Decode(asn.RawData);
- innerCms.CheckHash();
- if (innerCms.SignerInfos.Count > 0) {
- SignerInfo innerSignerInfo = innerCms.SignerInfos[0];
- innerSignerInfo.CheckSignature(false);
- if (VerifyTrust(expectedRootCa, innerSignerInfo.Certificate).Result) {
- VerifyFileHash(innerCms, innerSignerInfo);
- return; //success!
- }
- }
- }
+ return; //yes!
+ } catch {
+ //empty on purpose. keep checking...
}
+ } else {
+ Logger.Debug("Certificate is not one ziti verifies for: {0}", cert.Subject);
}
-
- throw new CryptographicException("No signing certificates found which meet the expected criteria");
}
+ throw new CryptographicException("Executable not signed by an appropriate certificate");
}
- */
+
public void VerifyFileHash(SignedCms cms, SignerInfo signerInfo) {
- if (!signerInfo.Certificate.Subject.ToLower().Contains("netfoundry")) {
- //just eject - no need to check this...
- Logger.Debug("Not verifying certificate as it is not a NetFoundry signing certificate: {0}", signerInfo.Certificate.Subject);
+ if (!IsCertificateOpenZitiVerifies(signerInfo.Certificate)) {
return;
}
+
//calculate the hash using the first signed info
var hashAlg = IncrementalHash.CreateHash(new HashAlgorithmName(signerInfo.DigestAlgorithm.FriendlyName.ToUpper()));
byte[] calculatedHash = CalculatePeHashStreaming(hashAlg);
@@ -223,7 +211,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
public async static Task VerifyTrust(X509Certificate2 trustedRootCertificateAuthority, X509Certificate2 certificate) {
- X509Store store = new X509Store("LocalMachine", StoreLocation.LocalMachine);
+ X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Chain chain = new X509Chain();
From 9b00b1b56762f0ef6633f904757aad26f8732436 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 14:41:55 -0400
Subject: [PATCH 05/19] version bump
---
Installer/ZitiDesktopEdge.aip | 4 ++--
version | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip
index 891569b9..044042c0 100644
--- a/Installer/ZitiDesktopEdge.aip
+++ b/Installer/ZitiDesktopEdge.aip
@@ -23,10 +23,10 @@
-
+
-
+
diff --git a/version b/version
index 7bc1c404..fee0a278 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.6
+1.9.7
From b0b7e2c4539a36025611b65f86b93f49b6d5304b Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 16:41:07 -0400
Subject: [PATCH 06/19] minor tweaks after testing
---
Installer/ZitiDesktopEdge.aip | 4 +-
.../checkers/PeFile/SignedFileValidator.cs | 40 ++++++++++---------
version | 2 +-
3 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip
index 044042c0..7bbedc5c 100644
--- a/Installer/ZitiDesktopEdge.aip
+++ b/Installer/ZitiDesktopEdge.aip
@@ -23,10 +23,10 @@
-
+
-
+
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 56ef02c8..65c1af82 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -26,8 +26,15 @@ namespace ZitiUpdateService.Checkers.PeFile {
public IMAGE_OPTIONAL_HEADER64 StandardFieldsPe32Plus { get; private set; }
private readonly X509Certificate2 expectedRootCa = null;
+ private readonly X509Store empty = new X509Store();
+ private X509Store SystemCAs = new X509Store();
public SignedFileValidator(string pathToFile) {
+ X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
+ store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
+ SystemCAs.Open(OpenFlags.ReadWrite);
+ SystemCAs.AddRange(store.Certificates);
+
expectedRootCa = certFromResource("ZitiUpdateService.checkers.PeFile.openziti.rootCA.rsa.pem.txt");
FilePath = pathToFile;
ImportantHashPositions = new HashPositions();
@@ -122,7 +129,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
//for indicating that the unsigned attributes contain the other SignerInfos
foreach (var cmsSi in cms.SignerInfos) {
cmsSi.CheckSignature(true);
- if (VerifyTrust(expectedRootCa, cmsSi.Certificate).Result) {
+ if (VerifyTrust(SystemCAs, expectedRootCa, cmsSi.Certificate).Result) {
VerifyFileHash(cms, cmsSi);
addCertToList(cmsSi, list);
}
@@ -152,7 +159,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
}
- if (VerifyTrust(expectedRootCa, innerSignerInfo.Certificate).Result) {
+ if (VerifyTrust(SystemCAs, expectedRootCa, innerSignerInfo.Certificate).Result) {
VerifyFileHash(innerCms, innerSignerInfo);
addCertToList(innerSignerInfo, list);
}
@@ -169,7 +176,9 @@ namespace ZitiUpdateService.Checkers.PeFile {
public bool IsCertificateOpenZitiVerifies(X509Certificate2 cert) {
bool yesOrNo = cert.Subject.ToLower().Contains("netfoundry") || cert.Subject.ToLower().Contains("openziti");
if (yesOrNo) {
- Logger.Debug("Certificate is one openziti verifies: {0}", cert.Subject);
+ Logger.Debug("Certificate does need verification: {0}", cert.Subject);
+ } else {
+ Logger.Debug("Certificate does not need verification: {0}", cert.Subject);
}
return yesOrNo;
}
@@ -180,14 +189,12 @@ namespace ZitiUpdateService.Checkers.PeFile {
if (IsCertificateOpenZitiVerifies(cert)) {
//verify this certificate was issued from the known CA
try {
- VerifyTrust(expectedRootCa, cert);
-
+ VerifyTrust(empty, expectedRootCa, cert, true).Wait();
+ Logger.Info("Certificate {0}:{1} was verified signed by {2}:{3}", cert.Thumbprint, cert.Subject, expectedRootCa.Thumbprint, expectedRootCa.Subject);
return; //yes!
} catch {
//empty on purpose. keep checking...
}
- } else {
- Logger.Debug("Certificate is not one ziti verifies for: {0}", cert.Subject);
}
}
throw new CryptographicException("Executable not signed by an appropriate certificate");
@@ -209,14 +216,14 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
}
- public async static Task VerifyTrust(X509Certificate2 trustedRootCertificateAuthority, X509Certificate2 certificate) {
+ public async static Task VerifyTrust(X509Store cas, X509Certificate2 trustedRootCertificateAuthority, X509Certificate2 certificate) {
+ return await VerifyTrust(cas, trustedRootCertificateAuthority, certificate, false);
+ }
- X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
- store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
-
+ public async static Task VerifyTrust(X509Store cas, X509Certificate2 trustedRootCertificateAuthority, X509Certificate2 certificate, bool verifyTrustedRoot) {
X509Chain chain = new X509Chain();
chain.ChainPolicy.ExtraStore.Add(trustedRootCertificateAuthority);
- chain.ChainPolicy.ExtraStore.AddRange(store.Certificates);
+ chain.ChainPolicy.ExtraStore.AddRange(cas.Certificates);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.Build(new X509Certificate2(certificate));
@@ -231,11 +238,10 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
//final check - make sure the last certificate matches the expected thumbprint
- if (chain.ChainElements[chain.ChainElements.Count - 1].Certificate.Thumbprint != trustedRootCertificateAuthority.Thumbprint) {
+ if (verifyTrustedRoot && chain.ChainElements[chain.ChainElements.Count - 1].Certificate.Thumbprint != trustedRootCertificateAuthority.Thumbprint) {
exceptions.Add(new Exception("Could not verify trust. The expected thumbprint was not found!"));
}
- bool crlFailure = false;
foreach (var e in certificate.Extensions) {
if (e.Oid.Value == "2.5.29.31") { //2.5.29.31 == CRL Distribution Points
try {
@@ -253,28 +259,24 @@ namespace ZitiUpdateService.Checkers.PeFile {
Win32Crypto.CrlInfo info = Win32Crypto.FromBlob(crlBytes);
if (info.RevokedSerialNumbers.Contains(certificate.SerialNumber)) {
exceptions.Add(new CryptographicException("Serial number " + certificate.SerialNumber + " has been revoked."));
- crlFailure = true;
}
} else {
exceptions.Add(new CryptographicException("Could not retrieve revocation list from " + url + "- cannot verify trust"));
- crlFailure = true;
}
}
catch (Exception innerException) {
exceptions.Add(new CryptographicException("crl at " + url + " could not be used", innerException));
- crlFailure = true;
}
}
}
}
catch (Exception ex) {
exceptions.Add(ex);
- break;
}
}
}
- if (crlFailure) {
+ if (exceptions.Count > 0) {
throw new AggregateException(exceptions);
}
diff --git a/version b/version
index fee0a278..66beabb5 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.7
+1.9.8
From 1fedec26335162516b5a27b7245c7052f8662f32 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 16:59:22 -0400
Subject: [PATCH 07/19] only allow for the one known thumbprint to report
expired not any cert
---
ZitiUpdateService/UpdateService.cs | 3 ---
.../checkers/PeFile/SignedFileValidator.cs | 15 ++++++++++-----
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index e423071e..3ea20548 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -34,12 +34,9 @@ namespace ZitiUpdateService {
public bool useGithubCheck { get; private set; }
- private static string[] expected_subject = new string[] { @"CN=""NetFoundry, Inc."", O=""NetFoundry, Inc."", L=Herndon, S=Virginia, C=US", @"CN=NetFoundry Inc., O=NetFoundry Inc., L=Herndon, S=Virginia, C=US" };
-
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private Timer _updateTimer = new Timer();
- private Timer openzitiRemovalTimer = new Timer();
private bool inUpdateCheck = false;
private string exeLocation = null;
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 65c1af82..0aeb81b2 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -28,6 +28,7 @@ namespace ZitiUpdateService.Checkers.PeFile {
private readonly X509Certificate2 expectedRootCa = null;
private readonly X509Store empty = new X509Store();
private X509Store SystemCAs = new X509Store();
+ private const string oldKnownThumbprint = "39636E9F5E80308DE370C914CE8112876ECF4E0C";
public SignedFileValidator(string pathToFile) {
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
@@ -144,8 +145,8 @@ namespace ZitiUpdateService.Checkers.PeFile {
try {
innerSignerInfo.CheckSignature(false);
}
- catch (CryptographicException ce) {
- if (innerSignerInfo.Certificate.Thumbprint == "39636E9F5E80308DE370C914CE8112876ECF4E0C") {
+ catch (CryptographicException) {
+ if (innerSignerInfo.Certificate.Thumbprint == oldKnownThumbprint) {
//special handling for the known 'old' NetFoundry signing certificate, now expired...
//TODO: remove this code after 2021
//just allow this one error
@@ -229,11 +230,15 @@ namespace ZitiUpdateService.Checkers.PeFile {
chain.Build(new X509Certificate2(certificate));
List exceptions = new List();
foreach (X509ChainStatus status in chain.ChainStatus) {
- if (status.Status == X509ChainStatusFlags.NoError || status.Status == X509ChainStatusFlags.UntrustedRoot || status.Status == X509ChainStatusFlags.NotTimeValid) {
+ if (status.Status == X509ChainStatusFlags.NoError || status.Status == X509ChainStatusFlags.UntrustedRoot) {
//X509ChainStatusFlags.UntrustedRoot simply means it was not found in the computer/user's trust store.... that's fine...
- //X509ChainStatusFlags.NotTimeValid means the certificate has expired - we're allowing this for now (summer 2021) to allow older clients to update
} else {
- exceptions.Add(new CryptographicException("Could not verify trust: " + status.StatusInformation));
+ if (status.Status == X509ChainStatusFlags.NotTimeValid && certificate.Thumbprint == oldKnownThumbprint) {
+ //X509ChainStatusFlags.NotTimeValid means the certificate has expired - we're allowing this for now (summer 2021) to allow older clients to update
+ Logger.Warn("Executable is signed using the old signing certificate. Allowing this certificate to report as expired");
+ } else {
+ exceptions.Add(new CryptographicException("Could not verify trust: " + status.StatusInformation));
+ }
}
}
From dad8cad74b47360b31cc70d03ca1de83595adf9e Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 17:24:28 -0400
Subject: [PATCH 08/19] add signing of exe to build script
---
Installer/build.ps1 | 8 +++++++-
ZitiDesktopEdge.sln | 2 ++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Installer/build.ps1 b/Installer/build.ps1
index 67c8559e..f9de8bc9 100644
--- a/Installer/build.ps1
+++ b/Installer/build.ps1
@@ -70,5 +70,11 @@ if($gituser -eq "ziti-ci") {
} else {
echo "detected user [${gituser}] which is not ziti-ci - skipping installer commit"
}
-(Get-FileHash "${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe").Hash > "${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe.sha256"
+
+$exeAbsPath="${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe"
+
+echo "adding additional signature to executable with openziti.org signing certificate"
+signtool sign /f "${env:PFXFILE_OPENZITI}" /p "${env:PFXPASS_OPENZITI}" /fd sha512 /td sha512 /as "${exeAbsPath}"
+
+(Get-FileHash "${exeAbsPath}").Hash > "${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe.sha256"
echo "========================== build.ps1 competed =========================="
diff --git a/ZitiDesktopEdge.sln b/ZitiDesktopEdge.sln
index 8167e22a..85a8a8ee 100644
--- a/ZitiDesktopEdge.sln
+++ b/ZitiDesktopEdge.sln
@@ -6,7 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D66B1C6A-ADFE-437E-B037-C4C849A6CA97}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
+ Installer\build.ps1 = Installer\build.ps1
README.md = README.md
+ Installer\reg.bat = Installer\reg.bat
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZitiDesktopEdge", "DesktopEdge\ZitiDesktopEdge.csproj", "{FA4291EA-A97E-4854-959F-91EE7B330B37}"
From d99c8b282ef4c9c72f8058ced9b962e3519f5c47 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 17:35:17 -0400
Subject: [PATCH 09/19] add /tr field to signing step
---
Installer/build.ps1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Installer/build.ps1 b/Installer/build.ps1
index f9de8bc9..8643a514 100644
--- a/Installer/build.ps1
+++ b/Installer/build.ps1
@@ -74,7 +74,7 @@ if($gituser -eq "ziti-ci") {
$exeAbsPath="${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe"
echo "adding additional signature to executable with openziti.org signing certificate"
-signtool sign /f "${env:PFXFILE_OPENZITI}" /p "${env:PFXPASS_OPENZITI}" /fd sha512 /td sha512 /as "${exeAbsPath}"
+signtool sign /f "${env:PFXFILE_OPENZITI}" /p "${env:PFXPASS_OPENZITI}" /tr http://ts.ssl.com /fd sha512 /td sha512 /as "${exeAbsPath}"
(Get-FileHash "${exeAbsPath}").Hash > "${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe.sha256"
echo "========================== build.ps1 competed =========================="
From 7ba5264aef57ffc5c20c2ebed6eb3a8e1a3a0842 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 18:34:21 -0400
Subject: [PATCH 10/19] very minor warning fixes
---
DesktopEdge/MainWindow.xaml.cs | 3 ++-
.../ServiceClient/AbstractClient.cs | 4 ++--
.../checkers/PeFile/SignedFileValidator.cs | 22 ++++++++++---------
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs
index 3e9bcdca..a727ff65 100644
--- a/DesktopEdge/MainWindow.xaml.cs
+++ b/DesktopEdge/MainWindow.xaml.cs
@@ -1439,7 +1439,8 @@ namespace ZitiDesktopEdge {
public bool CanExecute(object parameter) {
return true;
}
-
+#pragma warning disable CS0067 //The event 'ActionCommand.CanExecuteChanged' is never used
public event EventHandler CanExecuteChanged;
+#pragma warning restore CS0067 //The event 'ActionCommand.CanExecuteChanged' is never used
}
}
diff --git a/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs
index 4b90a28e..c5d96dca 100644
--- a/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs
+++ b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs
@@ -165,10 +165,10 @@ namespace ZitiDesktopEdge.ServiceClient {
} else {
//ClientDisconnected(null);
}
- } catch (Exception e) {
+ } catch (Exception) {
try {
ReconnectFailureEvent("reconnect failure");
- } catch (Exception ex){
+ } catch (Exception){
// don't care - just catch it and continue... it's a timeout...
}
var now = DateTime.Now;
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 0aeb81b2..3cc94d42 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -187,17 +187,19 @@ namespace ZitiUpdateService.Checkers.PeFile {
public void Verify() {
List list = ExtractVerifiedSignatureCertificates();
foreach (X509Certificate2 cert in list) {
- if (IsCertificateOpenZitiVerifies(cert)) {
- //verify this certificate was issued from the known CA
- try {
- VerifyTrust(empty, expectedRootCa, cert, true).Wait();
- Logger.Info("Certificate {0}:{1} was verified signed by {2}:{3}", cert.Thumbprint, cert.Subject, expectedRootCa.Thumbprint, expectedRootCa.Subject);
- return; //yes!
- } catch {
- //empty on purpose. keep checking...
- }
- }
+ if (IsCertificateOpenZitiVerifies(cert)) {
+ //verify this certificate was issued from the known CA
+ try {
+ VerifyTrust(empty, expectedRootCa, cert, true).Wait();
+ Logger.Info("Certificate {0}:{1} was verified signed by {2}:{3}", cert.Thumbprint, cert.Subject, expectedRootCa.Thumbprint, expectedRootCa.Subject);
+ return; //yes!
+ }
+ catch {
+ //empty on purpose. keep checking...
+ }
+ }
}
+
throw new CryptographicException("Executable not signed by an appropriate certificate");
}
From e2c54af6bcc7a8097a7ccb3d395c47a03044db9e Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 18:36:17 -0400
Subject: [PATCH 11/19] cleanup based on self-PR review
---
.../checkers/PeFile/SignedFileValidator.cs | 32 -------------------
service/cziti/dns-proxy.go | 3 --
2 files changed, 35 deletions(-)
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 3cc94d42..0a75f5f0 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -518,38 +518,6 @@ namespace ZitiUpdateService.Checkers.PeFile {
Pe32Plus
}
- public class CRLDistributionPointsParser {
- public static List GetCrlUrls(BinaryReader asn1Data) {
- //read the first byte - make sure it's marker 0x30 for SEQUENCE
- byte first = asn1Data.ReadByte();
- if (first != 0x30) {
- throw new CryptographicException("Could not parse CRL Distribution Points. First byte not asn marker");
- }
-
- if (first > 127) {
- //means there's more bytes to read that control the overall length of the next section
- }
- List rtn = new List();
-
- return rtn;
- }
-
- private static void readType(MemoryStream asn1Data) {
-
- }
-
- private static void readLen(byte lenByte, MemoryStream asn1Data) {
-
- }
- /*
- internal static CrlDistributionPointParser ParseTags(BinaryReader asn1Data, int asn1DataLen) {
-
- CrlDistributionPointParser tag = new CrlDistributionPointParser(asn1Data, asn1DataLen);
-
- return tag;
- }*/
- }
-
internal class CrlDistributionPointParser {
internal int offset;
internal int length;
diff --git a/service/cziti/dns-proxy.go b/service/cziti/dns-proxy.go
index 1e311972..94b1002a 100644
--- a/service/cziti/dns-proxy.go
+++ b/service/cziti/dns-proxy.go
@@ -354,7 +354,6 @@ outer:
for {
select {
case pr := <-proxiedRequests:
- log.Warnf("i am in proxiedRequests")
id := (uint32(pr.req.Id) << 16) | uint32(pr.req.Question[0].Qtype)
reqs[id] = pr
b, _ := pr.req.Pack()
@@ -377,7 +376,6 @@ outer:
}
case rep := <-respChan:
- log.Warnf("i am in respChan")
reply := dns.Msg{}
if err := reply.Unpack(rep); err == nil {
id := (uint32(reply.Id) << 16) | uint32(reply.Question[0].Qtype)
@@ -396,7 +394,6 @@ outer:
}
}
case <-time.After(time.Minute):
- log.Warnf("i am in time.After")
// cleanup requests we didn't get answers for
now := time.Now()
for k, r := range reqs {
From 22b3f6e7c7d679fe16787b8351887e8c26896c35 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 18:41:05 -0400
Subject: [PATCH 12/19] continued tiny fixes based on self-PR
---
ZitiUpdateService/UpdateService.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index 3ea20548..debe9e45 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -638,8 +638,8 @@ namespace ZitiUpdateService {
return;
}
Logger.Debug("downloaded file hash was correct. update can continue.");
-
- new SignedFileValidator(fileDestination).Verify();
+
+ new SignedFileValidator(fileDestination).Verify();
StopZiti();
StopUI().Wait();
From 75686c2084901d10c67280277cd9d8e635c34a15 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 19:04:43 -0400
Subject: [PATCH 13/19] small cleanup. update github action with new build
material needs
---
.github/workflows/installer.build.yml | 6 +++++-
Installer/build.ps1 | 2 +-
ZitiDesktopEdge.sln | 1 +
ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs | 6 +++++-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/installer.build.yml b/.github/workflows/installer.build.yml
index a08c08fa..a6acf427 100644
--- a/.github/workflows/installer.build.yml
+++ b/.github/workflows/installer.build.yml
@@ -22,7 +22,9 @@ jobs:
JFROG_ACCESS_TOKEN: ${{ secrets.JFROG_ACCESS_TOKEN }}
gh_ci_key: ${{ secrets.GH_CI_KEY }}
ZITI_DEBUG: "yes_please"
-
+ OPENZITI_P12_PASS: ${{ secrets.OPENZITI_P12_PASS }}
+ OPENZITI_P12: ${{ secrets.OPENZITI_P12 }}
+
steps:
- uses: actions/checkout@master
- uses: microsoft/setup-msbuild@v1
@@ -39,7 +41,9 @@ jobs:
run: |
echo "${env:SIGNING_CERT}" > WinSign.b64
echo "${env:ADV_INST_KEY}" > ADV_INST_KEY.key
+ echo "${env:OPENZITI_P12}" > OPENZITI_P12.b64
C:\Windows\System32\certutil.exe -decode WinSign.b64 Installer/WinSign.p12
+ C:\Windows\System32\certutil.exe -decode OPENZITI_P12.b64 Installer/openziti.p12
- name: Trying to run choco install.
run: Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
- name: "Install Choco needs: advanced-installer wixtoolset zip ninja"
diff --git a/Installer/build.ps1 b/Installer/build.ps1
index 8643a514..e0e51091 100644
--- a/Installer/build.ps1
+++ b/Installer/build.ps1
@@ -74,7 +74,7 @@ if($gituser -eq "ziti-ci") {
$exeAbsPath="${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe"
echo "adding additional signature to executable with openziti.org signing certificate"
-signtool sign /f "${env:PFXFILE_OPENZITI}" /p "${env:PFXPASS_OPENZITI}" /tr http://ts.ssl.com /fd sha512 /td sha512 /as "${exeAbsPath}"
+signtool sign /f "${scriptPath}\openziti.p12" /p "${env:OPENZITI_P12_PASS}" /tr http://ts.ssl.com /fd sha512 /td sha512 /as "${exeAbsPath}"
(Get-FileHash "${exeAbsPath}").Hash > "${scriptPath}\Output\Ziti Desktop Edge Client-${installerVersion}.exe.sha256"
echo "========================== build.ps1 competed =========================="
diff --git a/ZitiDesktopEdge.sln b/ZitiDesktopEdge.sln
index 85a8a8ee..70b973ed 100644
--- a/ZitiDesktopEdge.sln
+++ b/ZitiDesktopEdge.sln
@@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Installer\build.ps1 = Installer\build.ps1
+ .github\workflows\installer.build.yml = .github\workflows\installer.build.yml
README.md = README.md
Installer\reg.bat = Installer\reg.bat
EndProjectSection
diff --git a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
index 0a75f5f0..cb4ac576 100644
--- a/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
+++ b/ZitiUpdateService/checkers/PeFile/SignedFileValidator.cs
@@ -185,13 +185,17 @@ namespace ZitiUpdateService.Checkers.PeFile {
}
public void Verify() {
+ Logger.Debug("extracting certificates from file: {0}", FilePath);
List list = ExtractVerifiedSignatureCertificates();
+ Logger.Info("Certificates extracted: {0}", list.Count);
foreach (X509Certificate2 cert in list) {
+ Logger.Info("Checking certificate: [{0}] {1}", cert.Thumbprint, cert);
if (IsCertificateOpenZitiVerifies(cert)) {
//verify this certificate was issued from the known CA
try {
+ Logger.Info("Verifying trust of certificate: [{0}] {1}", cert, cert.Thumbprint);
VerifyTrust(empty, expectedRootCa, cert, true).Wait();
- Logger.Info("Certificate {0}:{1} was verified signed by {2}:{3}", cert.Thumbprint, cert.Subject, expectedRootCa.Thumbprint, expectedRootCa.Subject);
+ Logger.Info("Certificate [{0}] {1} was verified signed by [{2}] {3}", cert.Thumbprint, cert.Subject, expectedRootCa.Thumbprint, expectedRootCa.Subject);
return; //yes!
}
catch {
From b856254bdb5d86448e245415cca88c2b7cfd2819 Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Thu, 3 Jun 2021 19:06:53 -0400
Subject: [PATCH 14/19] this branch should be 1.9.7 not 1.9.8
---
version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version b/version
index 66beabb5..fee0a278 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.8
+1.9.7
From e47e9362333d765de2745913aecdd4aae11f96b9 Mon Sep 17 00:00:00 2001
From: Mary Lincy Dcouto
Date: Fri, 4 Jun 2021 16:34:12 +0530
Subject: [PATCH 15/19] updating t-sdk 0.15.7
---
release-notes.md | 14 ++++++++++++++
service/build.bat | 2 +-
version | 3 ++-
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/release-notes.md b/release-notes.md
index 611c4a40..0a509425 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,3 +1,17 @@
+# Release 1.9.7
+
+## What's New
+* none
+
+## Other changes:
+* none
+
+## Bugs fixed:
+* none
+
+## Dependency Updates
+* tsdk is updated to v0.15.7, c-sdk 0.23.3
+
# Release 1.9.6
## What's New
diff --git a/service/build.bat b/service/build.bat
index e1b6b27a..3c390e0c 100644
--- a/service/build.bat
+++ b/service/build.bat
@@ -14,7 +14,7 @@ REM See the License for the specific language governing permissions and
REM limitations under the License.
REM
SET REPO_URL=https://github.com/openziti/ziti-tunnel-sdk-c.git
-SET ZITI_TUNNEL_REPO_BRANCH=v0.15.6
+SET ZITI_TUNNEL_REPO_BRANCH=v0.15.7
REM override the c sdk used in the build - leave blank for the same as specified in the tunneler sdk
SET ZITI_SDK_C_BRANCH=
REM the number of TCP connections the tunneler sdk can have at any one time
diff --git a/version b/version
index 7bc1c404..d2435e46 100644
--- a/version
+++ b/version
@@ -1 +1,2 @@
-1.9.6
+
+1.9.7
From 6b51e19cdb2bc48678ca1a08d183cd6868db33ba Mon Sep 17 00:00:00 2001
From: dovholuknf <46322585+dovholuknf@users.noreply.github.com>
Date: Fri, 4 Jun 2021 12:01:36 -0400
Subject: [PATCH 16/19] use 1.9.8 for the version and cleanup silly typo in a
function name
---
ZitiUpdateService/checkers/PeFile/Win32Crypto.cs | 4 ++--
version | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs b/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
index a515baf6..b84dd21e 100644
--- a/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
+++ b/ZitiUpdateService/checkers/PeFile/Win32Crypto.cs
@@ -159,7 +159,7 @@ namespace VerifyingFiles.PInvoke {
#endregion
- private static List GetRevokedGetSerialNumbers(CRL_INFO stCrlInfo) {
+ private static List GetRevokedSerialNumbers(CRL_INFO stCrlInfo) {
List rtn = new List();
var rgCrlEntry = stCrlInfo.rgCRLEntry;
@@ -228,7 +228,7 @@ namespace VerifyingFiles.PInvoke {
CrlInfo info = new CrlInfo();
info.validTo = FileTimeToDateTime(stCrlInfo.NextUpdate);
info.validFrom = FileTimeToDateTime(stCrlInfo.ThisUpdate);
- info.RevokedSerialNumbers = GetRevokedGetSerialNumbers(stCrlInfo);
+ info.RevokedSerialNumbers = GetRevokedSerialNumbers(stCrlInfo);
return info;
} finally {
diff --git a/version b/version
index fee0a278..66beabb5 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.7
+1.9.8
From ee3ae6e2d5bb9521ea0ed8d3f1f1c348e8bc781f Mon Sep 17 00:00:00 2001
From: Mary Lincy Dcouto
Date: Fri, 4 Jun 2021 22:53:30 +0530
Subject: [PATCH 17/19] removing unnecessary space
---
version | 1 -
1 file changed, 1 deletion(-)
diff --git a/version b/version
index d2435e46..fee0a278 100644
--- a/version
+++ b/version
@@ -1,2 +1 @@
-
1.9.7
From 640510da9d7478ff0e4d9c5c95d1a3df504e949a Mon Sep 17 00:00:00 2001
From: ziti-ci
Date: Fri, 4 Jun 2021 17:33:18 +0000
Subject: [PATCH 18/19] [ci skip] committing updated version related files
---
DesktopEdge/Properties/AssemblyInfo.cs | 6 +++---
Installer/ZitiDesktopEdge.aip | 4 ++--
ZitiUpdateService/Properties/AssemblyInfo.cs | 6 +++---
service/ziti-tunnel/version.go | 8 ++++----
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs
index 69c6b337..7ae01ac7 100644
--- a/DesktopEdge/Properties/AssemblyInfo.cs
+++ b/DesktopEdge/Properties/AssemblyInfo.cs
@@ -50,6 +50,6 @@ using System.Windows;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyFileVersion("1.9.6.0")]
+// [assembly: AssemblyVersion("1.9.7.0")]
+[assembly: AssemblyVersion("1.9.7.0")]
+[assembly: AssemblyFileVersion("1.9.7.0")]
diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip
index 891569b9..af774c59 100644
--- a/Installer/ZitiDesktopEdge.aip
+++ b/Installer/ZitiDesktopEdge.aip
@@ -23,10 +23,10 @@
-
+
-
+
diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs
index 03a5efb4..40bb1b2b 100644
--- a/ZitiUpdateService/Properties/AssemblyInfo.cs
+++ b/ZitiUpdateService/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyFileVersion("1.9.6.0")]
+// [assembly: AssemblyVersion("1.9.7.0")]
+[assembly: AssemblyVersion("1.9.7.0")]
+[assembly: AssemblyFileVersion("1.9.7.0")]
diff --git a/service/ziti-tunnel/version.go b/service/ziti-tunnel/version.go
index 5305d2a9..e7912fd6 100644
--- a/service/ziti-tunnel/version.go
+++ b/service/ziti-tunnel/version.go
@@ -20,9 +20,9 @@
package main
const (
- Version = "1.9.6"
- Revision = "ed9a214d5c33"
- Branch = "main"
+ Version = "1.9.7"
+ Revision = "ee3ae6e2d5bb"
+ Branch = "release-next"
BuildUser = ""
- BuildDate = "2021-05-31 14:36:25"
+ BuildDate = "2021-06-04 17:27:26"
)
From df3de1f0ee8fcddefd178eb9bbc508cf6b3a3052 Mon Sep 17 00:00:00 2001
From: ziti-ci
Date: Mon, 7 Jun 2021 18:31:36 +0000
Subject: [PATCH 19/19] [ci skip] committing updated version related files
---
DesktopEdge/Properties/AssemblyInfo.cs | 6 +++---
ZitiUpdateService/Properties/AssemblyInfo.cs | 6 +++---
service/ziti-tunnel/version.go | 8 ++++----
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs
index 7ae01ac7..a9be57de 100644
--- a/DesktopEdge/Properties/AssemblyInfo.cs
+++ b/DesktopEdge/Properties/AssemblyInfo.cs
@@ -50,6 +50,6 @@ using System.Windows;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.7.0")]
-[assembly: AssemblyVersion("1.9.7.0")]
-[assembly: AssemblyFileVersion("1.9.7.0")]
+// [assembly: AssemblyVersion("1.9.8.0")]
+[assembly: AssemblyVersion("1.9.8.0")]
+[assembly: AssemblyFileVersion("1.9.8.0")]
diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs
index c384a42b..54e00a6d 100644
--- a/ZitiUpdateService/Properties/AssemblyInfo.cs
+++ b/ZitiUpdateService/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.6.0")]
-[assembly: AssemblyVersion("1.9.4.0")]
-[assembly: AssemblyFileVersion("1.9.4.0")]
+// [assembly: AssemblyVersion("1.9.8.0")]
+[assembly: AssemblyVersion("1.9.8.0")]
+[assembly: AssemblyFileVersion("1.9.8.0")]
diff --git a/service/ziti-tunnel/version.go b/service/ziti-tunnel/version.go
index e7912fd6..2307c033 100644
--- a/service/ziti-tunnel/version.go
+++ b/service/ziti-tunnel/version.go
@@ -20,9 +20,9 @@
package main
const (
- Version = "1.9.7"
- Revision = "ee3ae6e2d5bb"
- Branch = "release-next"
+ Version = "1.9.8"
+ Revision = "a763f2acac36"
+ Branch = "main"
BuildUser = ""
- BuildDate = "2021-06-04 17:27:26"
+ BuildDate = "2021-06-07 18:26:10"
)