diff options
35 files changed, 1033 insertions, 247 deletions
diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundlePayloadSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundlePayloadSymbol.cs index 82b75285..be581fb3 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundlePayloadSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundlePayloadSymbol.cs | |||
| @@ -26,6 +26,8 @@ namespace WixToolset.Data | |||
| 26 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.LayoutOnly), IntermediateFieldType.Bool), | 26 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.LayoutOnly), IntermediateFieldType.Bool), |
| 27 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.Packaging), IntermediateFieldType.Number), | 27 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.Packaging), IntermediateFieldType.Number), |
| 28 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.ParentPackagePayloadRef), IntermediateFieldType.String), | 28 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.ParentPackagePayloadRef), IntermediateFieldType.String), |
| 29 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.CertificatePublicKey), IntermediateFieldType.String), | ||
| 30 | new IntermediateFieldDefinition(nameof(WixBundlePayloadSymbolFields.CertificateThumbprint), IntermediateFieldType.String), | ||
| 29 | }, | 31 | }, |
| 30 | typeof(WixBundlePayloadSymbol)); | 32 | typeof(WixBundlePayloadSymbol)); |
| 31 | } | 33 | } |
| @@ -53,6 +55,8 @@ namespace WixToolset.Data.Symbols | |||
| 53 | LayoutOnly, | 55 | LayoutOnly, |
| 54 | Packaging, | 56 | Packaging, |
| 55 | ParentPackagePayloadRef, | 57 | ParentPackagePayloadRef, |
| 58 | CertificatePublicKey, | ||
| 59 | CertificateThumbprint, | ||
| 56 | } | 60 | } |
| 57 | 61 | ||
| 58 | public class WixBundlePayloadSymbol : IntermediateSymbol | 62 | public class WixBundlePayloadSymbol : IntermediateSymbol |
| @@ -162,5 +166,17 @@ namespace WixToolset.Data.Symbols | |||
| 162 | get => (string)this.Fields[(int)WixBundlePayloadSymbolFields.ParentPackagePayloadRef]; | 166 | get => (string)this.Fields[(int)WixBundlePayloadSymbolFields.ParentPackagePayloadRef]; |
| 163 | set => this.Set((int)WixBundlePayloadSymbolFields.ParentPackagePayloadRef, value); | 167 | set => this.Set((int)WixBundlePayloadSymbolFields.ParentPackagePayloadRef, value); |
| 164 | } | 168 | } |
| 169 | |||
| 170 | public string CertificatePublicKey | ||
| 171 | { | ||
| 172 | get => (string)this.Fields[(int)WixBundlePayloadSymbolFields.CertificatePublicKey]; | ||
| 173 | set => this.Set((int)WixBundlePayloadSymbolFields.CertificatePublicKey, value); | ||
| 174 | } | ||
| 175 | |||
| 176 | public string CertificateThumbprint | ||
| 177 | { | ||
| 178 | get => (string)this.Fields[(int)WixBundlePayloadSymbolFields.CertificateThumbprint]; | ||
| 179 | set => this.Set((int)WixBundlePayloadSymbolFields.CertificateThumbprint, value); | ||
| 180 | } | ||
| 165 | } | 181 | } |
| 166 | } | 182 | } |
diff --git a/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.v3.ncrunchproject b/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.v3.ncrunchproject new file mode 100644 index 00000000..cd54b69b --- /dev/null +++ b/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.v3.ncrunchproject | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | <ProjectConfiguration> | ||
| 2 | <Settings> | ||
| 3 | <HiddenComponentWarnings> | ||
| 4 | <Value>LostReference</Value> | ||
| 5 | </HiddenComponentWarnings> | ||
| 6 | </Settings> | ||
| 7 | </ProjectConfiguration> \ No newline at end of file | ||
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs index c8f10a71..af45e736 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs | |||
| @@ -672,7 +672,16 @@ namespace WixToolset.Core.Burn.Bundles | |||
| 672 | writer.WriteAttributeString("Id", payload.Id.Id); | 672 | writer.WriteAttributeString("Id", payload.Id.Id); |
| 673 | writer.WriteAttributeString("FilePath", payload.Name); | 673 | writer.WriteAttributeString("FilePath", payload.Name); |
| 674 | writer.WriteAttributeString("FileSize", payload.FileSize.Value.ToString(CultureInfo.InvariantCulture)); | 674 | writer.WriteAttributeString("FileSize", payload.FileSize.Value.ToString(CultureInfo.InvariantCulture)); |
| 675 | writer.WriteAttributeString("Hash", payload.Hash); | 675 | |
| 676 | if (!String.IsNullOrEmpty(payload.CertificatePublicKey) && !String.IsNullOrEmpty(payload.CertificateThumbprint)) | ||
| 677 | { | ||
| 678 | writer.WriteAttributeString("CertificateRootPublicKeyIdentifier", payload.CertificatePublicKey); | ||
| 679 | writer.WriteAttributeString("CertificateRootThumbprint", payload.CertificateThumbprint); | ||
| 680 | } | ||
| 681 | else | ||
| 682 | { | ||
| 683 | writer.WriteAttributeString("Hash", payload.Hash); | ||
| 684 | } | ||
| 676 | 685 | ||
| 677 | if (payload.LayoutOnly) | 686 | if (payload.LayoutOnly) |
| 678 | { | 687 | { |
diff --git a/src/wix/WixToolset.Core.Burn/BurnBackendErrors.cs b/src/wix/WixToolset.Core.Burn/BurnBackendErrors.cs index fd6eb093..74dc4cd5 100644 --- a/src/wix/WixToolset.Core.Burn/BurnBackendErrors.cs +++ b/src/wix/WixToolset.Core.Burn/BurnBackendErrors.cs | |||
| @@ -56,6 +56,11 @@ namespace WixToolset.Core.Burn | |||
| 56 | return Message(null, Ids.IncompatibleWixBurnSection, "Unable to read bundle executable '{0}', because this bundle was created with a different version of WiX burn (.wixburn section version '{1}'). You must use the same version of Windows Installer XML in order to read this bundle.", bundleExecutable, bundleVersion); | 56 | return Message(null, Ids.IncompatibleWixBurnSection, "Unable to read bundle executable '{0}', because this bundle was created with a different version of WiX burn (.wixburn section version '{1}'). You must use the same version of Windows Installer XML in order to read this bundle.", bundleExecutable, bundleVersion); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | public static Message UnsupportedRemotePackagePayload(string extension, string path) | ||
| 60 | { | ||
| 61 | return Message(null, Ids.UnsupportedRemotePackagePayload, "The first remote payload must be a supported package type of .exe or .msu. Use the -packageType switch to override the inferred extension: {0} from file: {1}", extension, path); | ||
| 62 | } | ||
| 63 | |||
| 59 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) | 64 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) |
| 60 | { | 65 | { |
| 61 | return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); | 66 | return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); |
| @@ -73,6 +78,7 @@ namespace WixToolset.Core.Burn | |||
| 73 | PackageCachePayloadCollision2 = 8007, | 78 | PackageCachePayloadCollision2 = 8007, |
| 74 | TooManyAttachedContainers = 8008, | 79 | TooManyAttachedContainers = 8008, |
| 75 | IncompatibleWixBurnSection = 8009, | 80 | IncompatibleWixBurnSection = 8009, |
| 81 | UnsupportedRemotePackagePayload = 8010, | ||
| 76 | } // last available is 8499. 8500 is BurnBackendWarnings. | 82 | } // last available is 8499. 8500 is BurnBackendWarnings. |
| 77 | } | 83 | } |
| 78 | } | 84 | } |
diff --git a/src/wix/WixToolset.Core.Burn/CommandLine/BurnCommand.cs b/src/wix/WixToolset.Core.Burn/CommandLine/BurnCommand.cs index a50fb7cd..b552678f 100644 --- a/src/wix/WixToolset.Core.Burn/CommandLine/BurnCommand.cs +++ b/src/wix/WixToolset.Core.Burn/CommandLine/BurnCommand.cs | |||
| @@ -52,6 +52,10 @@ namespace WixToolset.Core.Burn.CommandLine | |||
| 52 | case "reattach": | 52 | case "reattach": |
| 53 | this.Subcommand = new ReattachSubcommand(this.ServiceProvider); | 53 | this.Subcommand = new ReattachSubcommand(this.ServiceProvider); |
| 54 | return true; | 54 | return true; |
| 55 | |||
| 56 | case "remotepayload": | ||
| 57 | this.Subcommand = new RemotePayloadSubcommand(this.ServiceProvider); | ||
| 58 | return true; | ||
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | return false; | 61 | return false; |
diff --git a/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs new file mode 100644 index 00000000..7b362485 --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.Burn.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using System.Threading; | ||
| 10 | using System.Threading.Tasks; | ||
| 11 | using System.Xml.Linq; | ||
| 12 | using WixToolset.Core.Burn.Interfaces; | ||
| 13 | using WixToolset.Core.Native; | ||
| 14 | using WixToolset.Data; | ||
| 15 | using WixToolset.Data.Symbols; | ||
| 16 | using WixToolset.Extensibility.Services; | ||
| 17 | |||
| 18 | internal class RemotePayloadSubcommand : BurnSubcommandBase | ||
| 19 | { | ||
| 20 | private static readonly XName ExePackagePayloadName = "ExePackagePayload"; | ||
| 21 | private static readonly XName MsuPackagePayloadName = "MsuPackagePayload"; | ||
| 22 | private static readonly XName PayloadName = "Payload"; | ||
| 23 | |||
| 24 | public RemotePayloadSubcommand(IServiceProvider serviceProvider) | ||
| 25 | { | ||
| 26 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
| 27 | this.PayloadHarvester = serviceProvider.GetService<IPayloadHarvester>(); | ||
| 28 | } | ||
| 29 | |||
| 30 | private IMessaging Messaging { get; } | ||
| 31 | |||
| 32 | private IPayloadHarvester PayloadHarvester { get; } | ||
| 33 | |||
| 34 | private List<string> BasePaths { get; } = new List<string>(); | ||
| 35 | |||
| 36 | private string DownloadUrl { get; set; } | ||
| 37 | |||
| 38 | private List<string> InputPaths { get; } = new List<string>(); | ||
| 39 | |||
| 40 | private string OutputPath { get; set; } | ||
| 41 | |||
| 42 | private WixBundlePackageType? PackageType { get; set; } | ||
| 43 | |||
| 44 | private bool Recurse { get; set; } | ||
| 45 | |||
| 46 | private bool UseCertificate { get; set; } | ||
| 47 | |||
| 48 | public override Task<int> ExecuteAsync(CancellationToken cancellationToken) | ||
| 49 | { | ||
| 50 | var inputPaths = this.ExpandInputPaths(); | ||
| 51 | if (inputPaths.Count == 0) | ||
| 52 | { | ||
| 53 | Console.Error.WriteLine("Path to a remote payload is required"); | ||
| 54 | return Task.FromResult(-1); | ||
| 55 | } | ||
| 56 | |||
| 57 | // Reverse sort to ensure longest paths are matched first. | ||
| 58 | this.BasePaths.Sort(); | ||
| 59 | this.BasePaths.Reverse(); | ||
| 60 | |||
| 61 | var elements = this.HarvestRemotePayloads(inputPaths); | ||
| 62 | |||
| 63 | if (!this.Messaging.EncounteredError) | ||
| 64 | { | ||
| 65 | if (!String.IsNullOrEmpty(this.OutputPath)) | ||
| 66 | { | ||
| 67 | var outputFolder = Path.GetDirectoryName(this.OutputPath); | ||
| 68 | Directory.CreateDirectory(outputFolder); | ||
| 69 | |||
| 70 | File.WriteAllLines(this.OutputPath, elements.Select(e => e.ToString())); | ||
| 71 | } | ||
| 72 | else | ||
| 73 | { | ||
| 74 | foreach (var element in elements) | ||
| 75 | { | ||
| 76 | Console.WriteLine(element); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | return Task.FromResult(this.Messaging.LastErrorNumber); | ||
| 82 | } | ||
| 83 | |||
| 84 | public override bool TryParseArgument(ICommandLineParser parser, string argument) | ||
| 85 | { | ||
| 86 | if (parser.IsSwitch(argument)) | ||
| 87 | { | ||
| 88 | var parameter = argument.Substring(1); | ||
| 89 | switch (parameter.ToLowerInvariant()) | ||
| 90 | { | ||
| 91 | case "bp": | ||
| 92 | case "basepath": | ||
| 93 | this.BasePaths.Add(parser.GetNextArgumentAsDirectoryOrError(argument)); | ||
| 94 | return true; | ||
| 95 | |||
| 96 | case "du": | ||
| 97 | case "downloadurl": | ||
| 98 | this.DownloadUrl = parser.GetNextArgumentOrError(argument); | ||
| 99 | return true; | ||
| 100 | |||
| 101 | case "packagetype": | ||
| 102 | var packageTypeValue = parser.GetNextArgumentOrError(argument); | ||
| 103 | if (Enum.TryParse<WixBundlePackageType>(packageTypeValue, ignoreCase: true, out var packageType)) | ||
| 104 | { | ||
| 105 | this.PackageType = packageType; | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | break; | ||
| 109 | |||
| 110 | case "o": | ||
| 111 | case "out": | ||
| 112 | this.OutputPath = parser.GetNextArgumentAsFilePathOrError(argument); | ||
| 113 | return true; | ||
| 114 | |||
| 115 | case "r": | ||
| 116 | case "recurse": | ||
| 117 | this.Recurse = true; | ||
| 118 | return true; | ||
| 119 | |||
| 120 | case "usecertificate": | ||
| 121 | this.UseCertificate = true; | ||
| 122 | return true; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | else | ||
| 126 | { | ||
| 127 | this.InputPaths.Add(argument); | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | |||
| 131 | return false; | ||
| 132 | } | ||
| 133 | |||
| 134 | private IReadOnlyCollection<string> ExpandInputPaths() | ||
| 135 | { | ||
| 136 | var result = new List<string>(); | ||
| 137 | |||
| 138 | foreach (var inputPath in this.InputPaths) | ||
| 139 | { | ||
| 140 | var filename = Path.GetFileName(inputPath); | ||
| 141 | var folder = Path.GetDirectoryName(inputPath); | ||
| 142 | |||
| 143 | if (String.IsNullOrEmpty(folder)) | ||
| 144 | { | ||
| 145 | folder = "."; | ||
| 146 | } | ||
| 147 | |||
| 148 | foreach (var path in Directory.EnumerateFiles(folder, filename, this.Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)) | ||
| 149 | { | ||
| 150 | result.Add(path); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | return result.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); | ||
| 155 | } | ||
| 156 | |||
| 157 | private IEnumerable<XElement> HarvestRemotePayloads(IEnumerable<string> paths) | ||
| 158 | { | ||
| 159 | var first = true; | ||
| 160 | var hashes = new Dictionary<string, CertificateHashes>(); | ||
| 161 | |||
| 162 | if (this.UseCertificate) | ||
| 163 | { | ||
| 164 | hashes = CertificateHashes.Read(paths).Where(c => !String.IsNullOrEmpty(c.PublicKey) && !String.IsNullOrEmpty(c.Thumbprint) && c.Exception is null).ToDictionary(c => c.Path); | ||
| 165 | } | ||
| 166 | |||
| 167 | foreach (var path in paths) | ||
| 168 | { | ||
| 169 | var element = this.CreateRemotePayloadElement(path, first); | ||
| 170 | first = false; | ||
| 171 | |||
| 172 | if (element == null) | ||
| 173 | { | ||
| 174 | continue; | ||
| 175 | } | ||
| 176 | |||
| 177 | var payloadSymbol = new WixBundlePayloadSymbol | ||
| 178 | { | ||
| 179 | SourceFile = new IntermediateFieldPathValue { Path = path }, | ||
| 180 | }; | ||
| 181 | |||
| 182 | this.PayloadHarvester.HarvestStandardInformation(payloadSymbol); | ||
| 183 | |||
| 184 | element.Add(new XAttribute("Name", Path.GetFileName(path))); | ||
| 185 | |||
| 186 | if (!String.IsNullOrEmpty(payloadSymbol.DisplayName)) | ||
| 187 | { | ||
| 188 | element.Add(new XAttribute("ProductName", payloadSymbol.DisplayName)); | ||
| 189 | } | ||
| 190 | |||
| 191 | if (!String.IsNullOrEmpty(payloadSymbol.Description)) | ||
| 192 | { | ||
| 193 | element.Add(new XAttribute("Description", payloadSymbol.Description)); | ||
| 194 | } | ||
| 195 | |||
| 196 | if (!String.IsNullOrEmpty(this.DownloadUrl)) | ||
| 197 | { | ||
| 198 | var filename = this.GetRelativeFileName(payloadSymbol.SourceFile.Path); | ||
| 199 | var formattedUrl = String.Format(this.DownloadUrl, filename); | ||
| 200 | |||
| 201 | if (Uri.TryCreate(formattedUrl, UriKind.Absolute, out var url)) | ||
| 202 | { | ||
| 203 | element.Add(new XAttribute("DownloadUrl", url.AbsoluteUri)); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | if (hashes.TryGetValue(path, out var certificateHashes)) | ||
| 208 | { | ||
| 209 | element.Add(new XAttribute("CertificatePublicKey", certificateHashes.PublicKey)); | ||
| 210 | element.Add(new XAttribute("CertificateThumbprint", certificateHashes.Thumbprint)); | ||
| 211 | } | ||
| 212 | |||
| 213 | if (!String.IsNullOrEmpty(payloadSymbol.Hash)) | ||
| 214 | { | ||
| 215 | element.Add(new XAttribute("Hash", payloadSymbol.Hash)); | ||
| 216 | } | ||
| 217 | |||
| 218 | if (payloadSymbol.FileSize.HasValue) | ||
| 219 | { | ||
| 220 | element.Add(new XAttribute("Size", payloadSymbol.FileSize.Value)); | ||
| 221 | } | ||
| 222 | |||
| 223 | if (!String.IsNullOrEmpty(payloadSymbol.Version)) | ||
| 224 | { | ||
| 225 | element.Add(new XAttribute("Version", payloadSymbol.Version)); | ||
| 226 | } | ||
| 227 | |||
| 228 | yield return element; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | private XElement CreateRemotePayloadElement(string path, bool firstHarvest) | ||
| 233 | { | ||
| 234 | if (firstHarvest) | ||
| 235 | { | ||
| 236 | var extension = this.PackageType.HasValue ? this.PackageType.ToString() : Path.GetExtension(path); | ||
| 237 | |||
| 238 | switch (extension.ToUpperInvariant()) | ||
| 239 | { | ||
| 240 | case "EXE": | ||
| 241 | case ".EXE": | ||
| 242 | return new XElement(ExePackagePayloadName); | ||
| 243 | |||
| 244 | case "MSU": | ||
| 245 | case ".MSU": | ||
| 246 | return new XElement(MsuPackagePayloadName); | ||
| 247 | |||
| 248 | default: | ||
| 249 | this.Messaging.Write(BurnBackendErrors.UnsupportedRemotePackagePayload(extension, path)); | ||
| 250 | return null; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | else | ||
| 254 | { | ||
| 255 | return new XElement(PayloadName); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | private string GetRelativeFileName(string path) | ||
| 260 | { | ||
| 261 | foreach (var basePath in this.BasePaths) | ||
| 262 | { | ||
| 263 | if (path.StartsWith(basePath, StringComparison.OrdinalIgnoreCase)) | ||
| 264 | { | ||
| 265 | return path.Substring(basePath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | return Path.GetFileName(path); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
diff --git a/src/wix/WixToolset.Core.Native/CertificateHashes.cs b/src/wix/WixToolset.Core.Native/CertificateHashes.cs new file mode 100644 index 00000000..a024c923 --- /dev/null +++ b/src/wix/WixToolset.Core.Native/CertificateHashes.cs | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.Native | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.ComponentModel; | ||
| 8 | using System.Globalization; | ||
| 9 | using System.Linq; | ||
| 10 | |||
| 11 | /// <summary> | ||
| 12 | /// Read certificates' public key and thumbprint hashes. | ||
| 13 | /// </summary> | ||
| 14 | public sealed class CertificateHashes | ||
| 15 | { | ||
| 16 | private static readonly char[] TextLineSplitter = new[] { '\t' }; | ||
| 17 | |||
| 18 | private CertificateHashes(string path, string publicKey, string thumbprint, Exception exception) | ||
| 19 | { | ||
| 20 | this.Path = path; | ||
| 21 | this.PublicKey = publicKey; | ||
| 22 | this.Thumbprint = thumbprint; | ||
| 23 | this.Exception = exception; | ||
| 24 | } | ||
| 25 | |||
| 26 | /// <summary> | ||
| 27 | /// Path to the file read. | ||
| 28 | /// </summary> | ||
| 29 | public string Path { get; } | ||
| 30 | |||
| 31 | /// <summary> | ||
| 32 | /// Hash of the certificate's public key. | ||
| 33 | /// </summary> | ||
| 34 | public string PublicKey { get; } | ||
| 35 | |||
| 36 | /// <summary> | ||
| 37 | /// Hash of the certificate's thumbprint. | ||
| 38 | /// </summary> | ||
| 39 | public string Thumbprint { get; } | ||
| 40 | |||
| 41 | /// <summary> | ||
| 42 | /// Exception encountered while trying to read certificate's hash. | ||
| 43 | /// </summary> | ||
| 44 | public Exception Exception { get; } | ||
| 45 | |||
| 46 | /// <summary> | ||
| 47 | /// Read the certificate hashes from the provided paths. | ||
| 48 | /// </summary> | ||
| 49 | /// <param name="paths">Paths to read for certificates.</param> | ||
| 50 | /// <returns>Certificate hashes for the provided paths.</returns> | ||
| 51 | public static IReadOnlyList<CertificateHashes> Read(IEnumerable<string> paths) | ||
| 52 | { | ||
| 53 | var result = new List<CertificateHashes>(); | ||
| 54 | |||
| 55 | var wixnative = new WixNativeExe("certhashes"); | ||
| 56 | |||
| 57 | foreach (var path in paths) | ||
| 58 | { | ||
| 59 | wixnative.AddStdinLine(path); | ||
| 60 | } | ||
| 61 | |||
| 62 | try | ||
| 63 | { | ||
| 64 | var outputLines = wixnative.Run(); | ||
| 65 | foreach (var line in outputLines.Where(l => !String.IsNullOrEmpty(l))) | ||
| 66 | { | ||
| 67 | var data = line.Split(TextLineSplitter, StringSplitOptions.None); | ||
| 68 | |||
| 69 | var error = Int32.Parse(data[3].Substring(2), NumberStyles.HexNumber); | ||
| 70 | var exception = error != 0 ? new Win32Exception(error) : null; | ||
| 71 | |||
| 72 | result.Add(new CertificateHashes(data[0], data[1], data[2], exception)); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | catch (Exception e) | ||
| 76 | { | ||
| 77 | result.Add(new CertificateHashes(null, null, null, e)); | ||
| 78 | } | ||
| 79 | |||
| 80 | return result; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
diff --git a/src/wix/WixToolset.Core.Native/WixNativeExe.cs b/src/wix/WixToolset.Core.Native/WixNativeExe.cs index 13d7a4ea..f5ff8bf0 100644 --- a/src/wix/WixToolset.Core.Native/WixNativeExe.cs +++ b/src/wix/WixToolset.Core.Native/WixNativeExe.cs | |||
| @@ -30,7 +30,7 @@ namespace WixToolset.Core.Native | |||
| 30 | this.stdinLines.AddRange(lines); | 30 | this.stdinLines.AddRange(lines); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | public IEnumerable<string> Run() | 33 | public IReadOnlyCollection<string> Run() |
| 34 | { | 34 | { |
| 35 | EnsurePathToWixNativeExeSet(); | 35 | EnsurePathToWixNativeExeSet(); |
| 36 | 36 | ||
diff --git a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs index ea63ee8c..cee9b377 100644 --- a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs +++ b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs | |||
| @@ -11,12 +11,31 @@ namespace WixToolset.Core | |||
| 11 | 11 | ||
| 12 | internal class CompilerPayload | 12 | internal class CompilerPayload |
| 13 | { | 13 | { |
| 14 | public string Version { get; set; } | ||
| 15 | |||
| 16 | public CompilerPayload(CompilerCore core, SourceLineNumber sourceLineNumbers, XElement element) | ||
| 17 | { | ||
| 18 | this.Core = core; | ||
| 19 | this.Element = element; | ||
| 20 | this.SourceLineNumbers = sourceLineNumbers; | ||
| 21 | } | ||
| 22 | |||
| 23 | private CompilerCore Core { get; } | ||
| 24 | |||
| 25 | private XElement Element { get; } | ||
| 26 | |||
| 27 | private SourceLineNumber SourceLineNumbers { get; } | ||
| 28 | |||
| 14 | public YesNoDefaultType Compressed { get; set; } = YesNoDefaultType.Default; | 29 | public YesNoDefaultType Compressed { get; set; } = YesNoDefaultType.Default; |
| 15 | 30 | ||
| 16 | public string Description { get; set; } | 31 | public string Description { get; set; } |
| 17 | 32 | ||
| 18 | public string DownloadUrl { get; set; } | 33 | public string DownloadUrl { get; set; } |
| 19 | 34 | ||
| 35 | public string CertificatePublicKey { get; set; } | ||
| 36 | |||
| 37 | public string CertificateThumbprint { get; set; } | ||
| 38 | |||
| 20 | public string Hash { get; set; } | 39 | public string Hash { get; set; } |
| 21 | 40 | ||
| 22 | public Identifier Id { get; set; } | 41 | public Identifier Id { get; set; } |
| @@ -33,24 +52,9 @@ namespace WixToolset.Core | |||
| 33 | 52 | ||
| 34 | public string SourceFile { get; set; } | 53 | public string SourceFile { get; set; } |
| 35 | 54 | ||
| 36 | public string Version { get; set; } | ||
| 37 | |||
| 38 | public CompilerPayload(CompilerCore core, SourceLineNumber sourceLineNumbers, XElement element) | ||
| 39 | { | ||
| 40 | this.Core = core; | ||
| 41 | this.Element = element; | ||
| 42 | this.SourceLineNumbers = sourceLineNumbers; | ||
| 43 | } | ||
| 44 | |||
| 45 | private CompilerCore Core { get; } | ||
| 46 | |||
| 47 | private XElement Element { get; } | ||
| 48 | |||
| 49 | private SourceLineNumber SourceLineNumbers { get; } | ||
| 50 | |||
| 51 | private void CalculateAndVerifyFields() | 55 | private void CalculateAndVerifyFields() |
| 52 | { | 56 | { |
| 53 | var isRemote = this.IsRemoteAllowed && !String.IsNullOrEmpty(this.Hash); | 57 | var isRemote = this.IsRemoteAllowed && (!String.IsNullOrEmpty(this.CertificatePublicKey) || !String.IsNullOrEmpty(this.CertificateThumbprint) || !String.IsNullOrEmpty(this.Hash)); |
| 54 | 58 | ||
| 55 | if (String.IsNullOrEmpty(this.SourceFile)) | 59 | if (String.IsNullOrEmpty(this.SourceFile)) |
| 56 | { | 60 | { |
| @@ -81,7 +85,7 @@ namespace WixToolset.Core | |||
| 81 | } | 85 | } |
| 82 | else | 86 | else |
| 83 | { | 87 | { |
| 84 | this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "SourceFile", "Hash")); | 88 | this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "SourceFile", "CertificatePublicKey", "Hash")); |
| 85 | } | 89 | } |
| 86 | } | 90 | } |
| 87 | } | 91 | } |
| @@ -93,7 +97,20 @@ namespace WixToolset.Core | |||
| 93 | { | 97 | { |
| 94 | if (isRemote) | 98 | if (isRemote) |
| 95 | { | 99 | { |
| 96 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile")); | 100 | if (!String.IsNullOrEmpty(this.Hash)) |
| 101 | { | ||
| 102 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile")); | ||
| 103 | } | ||
| 104 | |||
| 105 | if (!String.IsNullOrEmpty(this.CertificatePublicKey)) | ||
| 106 | { | ||
| 107 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificatePublicKey", "SourceFile")); | ||
| 108 | } | ||
| 109 | |||
| 110 | if (!String.IsNullOrEmpty(this.CertificateThumbprint)) | ||
| 111 | { | ||
| 112 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificateThumbprint", "SourceFile")); | ||
| 113 | } | ||
| 97 | } | 114 | } |
| 98 | 115 | ||
| 99 | if (!String.IsNullOrEmpty(this.Description)) | 116 | if (!String.IsNullOrEmpty(this.Description)) |
| @@ -120,17 +137,34 @@ namespace WixToolset.Core | |||
| 120 | { | 137 | { |
| 121 | if (String.IsNullOrEmpty(this.DownloadUrl)) | 138 | if (String.IsNullOrEmpty(this.DownloadUrl)) |
| 122 | { | 139 | { |
| 123 | this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "Hash")); | 140 | this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "SourceFile")); |
| 124 | } | 141 | } |
| 125 | 142 | ||
| 126 | if (String.IsNullOrEmpty(this.Name)) | 143 | if (String.IsNullOrEmpty(this.Name)) |
| 127 | { | 144 | { |
| 128 | this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "Hash")); | 145 | this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile")); |
| 129 | } | 146 | } |
| 130 | 147 | ||
| 131 | if (!this.Size.HasValue) | 148 | if (!this.Size.HasValue) |
| 132 | { | 149 | { |
| 133 | this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Size", "Hash")); | 150 | this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Size", "SourceFile")); |
| 151 | } | ||
| 152 | |||
| 153 | if (String.IsNullOrEmpty(this.Hash)) | ||
| 154 | { | ||
| 155 | this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile")); | ||
| 156 | } | ||
| 157 | |||
| 158 | if (!String.IsNullOrEmpty(this.CertificatePublicKey) || !String.IsNullOrEmpty(this.CertificateThumbprint)) | ||
| 159 | { | ||
| 160 | if (String.IsNullOrEmpty(this.CertificateThumbprint)) | ||
| 161 | { | ||
| 162 | this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificateThumbprint", "CertificatePublicKey")); | ||
| 163 | } | ||
| 164 | else if (String.IsNullOrEmpty(this.CertificatePublicKey)) | ||
| 165 | { | ||
| 166 | this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificatePublicKey", "CertificateThumbprint")); | ||
| 167 | } | ||
| 134 | } | 168 | } |
| 135 | 169 | ||
| 136 | if (YesNoDefaultType.Yes == this.Compressed) | 170 | if (YesNoDefaultType.Yes == this.Compressed) |
| @@ -177,6 +211,8 @@ namespace WixToolset.Core | |||
| 177 | Hash = this.Hash, | 211 | Hash = this.Hash, |
| 178 | FileSize = this.Size, | 212 | FileSize = this.Size, |
| 179 | Version = this.Version, | 213 | Version = this.Version, |
| 214 | CertificatePublicKey = this.CertificatePublicKey, | ||
| 215 | CertificateThumbprint = this.CertificateThumbprint | ||
| 180 | }); | 216 | }); |
| 181 | 217 | ||
| 182 | this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, ComplexReferenceChildType.Unknown, null); | 218 | this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, ComplexReferenceChildType.Unknown, null); |
| @@ -248,6 +284,16 @@ namespace WixToolset.Core | |||
| 248 | this.DownloadUrl = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); | 284 | this.DownloadUrl = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); |
| 249 | } | 285 | } |
| 250 | 286 | ||
| 287 | public void ParseCertificatePublicKey(XAttribute attrib) | ||
| 288 | { | ||
| 289 | this.CertificatePublicKey = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); | ||
| 290 | } | ||
| 291 | |||
| 292 | public void ParseCertificateThumbprint(XAttribute attrib) | ||
| 293 | { | ||
| 294 | this.CertificateThumbprint = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); | ||
| 295 | } | ||
| 296 | |||
| 251 | public void ParseHash(XAttribute attrib) | 297 | public void ParseHash(XAttribute attrib) |
| 252 | { | 298 | { |
| 253 | this.Hash = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); | 299 | this.Hash = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); |
| @@ -286,6 +332,5 @@ namespace WixToolset.Core | |||
| 286 | { | 332 | { |
| 287 | this.Version = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); | 333 | this.Version = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib); |
| 288 | } | 334 | } |
| 289 | |||
| 290 | } | 335 | } |
| 291 | } | 336 | } |
diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs index c8b78243..3fde990e 100644 --- a/src/wix/WixToolset.Core/Compiler_Bundle.cs +++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs | |||
| @@ -2459,6 +2459,20 @@ namespace WixToolset.Core | |||
| 2459 | case "SourceFile": | 2459 | case "SourceFile": |
| 2460 | compilerPayload.ParseSourceFile(attrib); | 2460 | compilerPayload.ParseSourceFile(attrib); |
| 2461 | break; | 2461 | break; |
| 2462 | case "CertificatePublicKey": | ||
| 2463 | allowed = compilerPayload.IsRemoteAllowed; | ||
| 2464 | if (allowed) | ||
| 2465 | { | ||
| 2466 | compilerPayload.ParseCertificatePublicKey(attrib); | ||
| 2467 | } | ||
| 2468 | break; | ||
| 2469 | case "CertificateThumbprint": | ||
| 2470 | allowed = compilerPayload.IsRemoteAllowed; | ||
| 2471 | if (allowed) | ||
| 2472 | { | ||
| 2473 | compilerPayload.ParseCertificateThumbprint(attrib); | ||
| 2474 | } | ||
| 2475 | break; | ||
| 2462 | case "DownloadUrl": | 2476 | case "DownloadUrl": |
| 2463 | compilerPayload.ParseDownloadUrl(attrib); | 2477 | compilerPayload.ParseDownloadUrl(attrib); |
| 2464 | break; | 2478 | break; |
diff --git a/src/wix/heat/PayloadHarvester.cs b/src/wix/heat/PayloadHarvester.cs deleted file mode 100644 index d2492512..00000000 --- a/src/wix/heat/PayloadHarvester.cs +++ /dev/null | |||
| @@ -1,129 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Harvesters | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using WixToolset.Core.Burn.Interfaces; | ||
| 8 | using WixToolset.Data; | ||
| 9 | using WixToolset.Data.Symbols; | ||
| 10 | using WixToolset.Harvesters.Data; | ||
| 11 | using WixToolset.Harvesters.Extensibility; | ||
| 12 | using Wix = WixToolset.Harvesters.Serialize; | ||
| 13 | |||
| 14 | /// <summary> | ||
| 15 | /// Harvest WiX authoring for a payload from the file system. | ||
| 16 | /// </summary> | ||
| 17 | public sealed class PayloadHarvester : BaseHarvesterExtension | ||
| 18 | { | ||
| 19 | private bool setUniqueIdentifiers; | ||
| 20 | private WixBundlePackageType packageType; | ||
| 21 | |||
| 22 | private IPayloadHarvester payloadHarvester; | ||
| 23 | |||
| 24 | /// <summary> | ||
| 25 | /// Instantiate a new PayloadHarvester. | ||
| 26 | /// </summary> | ||
| 27 | public PayloadHarvester(IPayloadHarvester payloadHarvester, WixBundlePackageType packageType) | ||
| 28 | { | ||
| 29 | this.payloadHarvester = payloadHarvester; | ||
| 30 | |||
| 31 | this.packageType = packageType; | ||
| 32 | this.setUniqueIdentifiers = true; | ||
| 33 | } | ||
| 34 | |||
| 35 | /// <summary> | ||
| 36 | /// Gets of sets the option to set unique identifiers. | ||
| 37 | /// </summary> | ||
| 38 | /// <value>The option to set unique identifiers.</value> | ||
| 39 | public bool SetUniqueIdentifiers | ||
| 40 | { | ||
| 41 | get { return this.setUniqueIdentifiers; } | ||
| 42 | set { this.setUniqueIdentifiers = value; } | ||
| 43 | } | ||
| 44 | |||
| 45 | /// <summary> | ||
| 46 | /// Harvest a payload. | ||
| 47 | /// </summary> | ||
| 48 | /// <param name="argument">The path of the payload.</param> | ||
| 49 | /// <returns>A harvested payload.</returns> | ||
| 50 | public override Wix.Fragment[] Harvest(string argument) | ||
| 51 | { | ||
| 52 | if (null == argument) | ||
| 53 | { | ||
| 54 | throw new ArgumentNullException("argument"); | ||
| 55 | } | ||
| 56 | |||
| 57 | string fullPath = Path.GetFullPath(argument); | ||
| 58 | |||
| 59 | var remotePayload = this.HarvestRemotePayload(fullPath); | ||
| 60 | |||
| 61 | var fragment = new Wix.Fragment(); | ||
| 62 | fragment.AddChild(remotePayload); | ||
| 63 | |||
| 64 | return new Wix.Fragment[] { fragment }; | ||
| 65 | } | ||
| 66 | |||
| 67 | /// <summary> | ||
| 68 | /// Harvest a payload. | ||
| 69 | /// </summary> | ||
| 70 | /// <param name="path">The path of the payload.</param> | ||
| 71 | /// <returns>A harvested payload.</returns> | ||
| 72 | public Wix.RemotePayload HarvestRemotePayload(string path) | ||
| 73 | { | ||
| 74 | if (null == path) | ||
| 75 | { | ||
| 76 | throw new ArgumentNullException("path"); | ||
| 77 | } | ||
| 78 | |||
| 79 | if (!File.Exists(path)) | ||
| 80 | { | ||
| 81 | throw new WixException(HarvesterErrors.FileNotFound(path)); | ||
| 82 | } | ||
| 83 | |||
| 84 | Wix.RemotePayload remotePayload; | ||
| 85 | |||
| 86 | switch (this.packageType) | ||
| 87 | { | ||
| 88 | case WixBundlePackageType.Exe: | ||
| 89 | remotePayload = new Wix.ExePackagePayload(); | ||
| 90 | break; | ||
| 91 | case WixBundlePackageType.Msu: | ||
| 92 | remotePayload = new Wix.MsuPackagePayload(); | ||
| 93 | break; | ||
| 94 | default: | ||
| 95 | throw new NotImplementedException(); | ||
| 96 | } | ||
| 97 | |||
| 98 | var payloadSymbol = new WixBundlePayloadSymbol | ||
| 99 | { | ||
| 100 | SourceFile = new IntermediateFieldPathValue { Path = path }, | ||
| 101 | }; | ||
| 102 | |||
| 103 | this.payloadHarvester.HarvestStandardInformation(payloadSymbol); | ||
| 104 | |||
| 105 | if (payloadSymbol.FileSize.HasValue) | ||
| 106 | { | ||
| 107 | remotePayload.Size = payloadSymbol.FileSize.Value; | ||
| 108 | } | ||
| 109 | remotePayload.Hash = payloadSymbol.Hash; | ||
| 110 | |||
| 111 | if (!String.IsNullOrEmpty(payloadSymbol.Version)) | ||
| 112 | { | ||
| 113 | remotePayload.Version = payloadSymbol.Version; | ||
| 114 | } | ||
| 115 | |||
| 116 | if (!String.IsNullOrEmpty(payloadSymbol.Description)) | ||
| 117 | { | ||
| 118 | remotePayload.Description = payloadSymbol.Description; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (!String.IsNullOrEmpty(payloadSymbol.DisplayName)) | ||
| 122 | { | ||
| 123 | remotePayload.ProductName = payloadSymbol.DisplayName; | ||
| 124 | } | ||
| 125 | |||
| 126 | return remotePayload; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
diff --git a/src/wix/heat/UtilHeatExtension.cs b/src/wix/heat/UtilHeatExtension.cs index e5be9cac..5ad5ef8a 100644 --- a/src/wix/heat/UtilHeatExtension.cs +++ b/src/wix/heat/UtilHeatExtension.cs | |||
| @@ -87,14 +87,6 @@ namespace WixToolset.Harvesters | |||
| 87 | harvesterExtension = new FileHarvester(); | 87 | harvesterExtension = new FileHarvester(); |
| 88 | active = true; | 88 | active = true; |
| 89 | break; | 89 | break; |
| 90 | case "exepackagepayload": | ||
| 91 | harvesterExtension = new PayloadHarvester(this.PayloadHarvester, WixBundlePackageType.Exe); | ||
| 92 | active = true; | ||
| 93 | break; | ||
| 94 | case "msupackagepayload": | ||
| 95 | harvesterExtension = new PayloadHarvester(this.PayloadHarvester, WixBundlePackageType.Msu); | ||
| 96 | active = true; | ||
| 97 | break; | ||
| 98 | case "perf": | 90 | case "perf": |
| 99 | harvesterExtension = new PerformanceCategoryHarvester(); | 91 | harvesterExtension = new PerformanceCategoryHarvester(); |
| 100 | active = true; | 92 | active = true; |
diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject index 18ab4f79..b8c570ae 100644 --- a/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | <ProjectConfiguration> | 1 | <ProjectConfiguration> |
| 2 | <Settings> | 2 | <Settings> |
| 3 | <HiddenComponentWarnings> | ||
| 4 | <Value>LostReference</Value> | ||
| 5 | </HiddenComponentWarnings> | ||
| 3 | <IgnoredTests> | 6 | <IgnoredTests> |
| 4 | <NamedTestSelector> | 7 | <NamedTestSelector> |
| 5 | <TestName>WixToolsetTest.Converters.Symbolizer.ConvertSymbolsFixture.CanLoadWixoutAndConvertToIntermediate</TestName> | 8 | <TestName>WixToolsetTest.Converters.Symbolizer.ConvertSymbolsFixture.CanLoadWixoutAndConvertToIntermediate</TestName> |
diff --git a/src/wix/test/WixToolsetTest.Core.Native/CertificateHashesFixture.cs b/src/wix/test/WixToolsetTest.Core.Native/CertificateHashesFixture.cs new file mode 100644 index 00000000..5783445b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Core.Native/CertificateHashesFixture.cs | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.CoreNative | ||
| 4 | { | ||
| 5 | using System.ComponentModel; | ||
| 6 | using System.Linq; | ||
| 7 | using WixToolset.Core.Native; | ||
| 8 | using WixToolsetTest.CoreNative.Utility; | ||
| 9 | using Xunit; | ||
| 10 | |||
| 11 | public class CertificateHashesFixture | ||
| 12 | { | ||
| 13 | [Fact] | ||
| 14 | public void CanGetHashesFromSignedFile() | ||
| 15 | { | ||
| 16 | var cabFile = TestData.Get(@"TestData\test.cab"); | ||
| 17 | |||
| 18 | var hashes = CertificateHashes.Read(new[] { cabFile }); | ||
| 19 | |||
| 20 | var hash = hashes.Single(); | ||
| 21 | Assert.Equal(cabFile, hash.Path); | ||
| 22 | Assert.Equal("7EC90B3FC3D580EB571210011F1095E149DCC6BB", hash.PublicKey); | ||
| 23 | Assert.Equal("0B13494DB50BC185A34389BBBAA01EDD1CF56350", hash.Thumbprint); | ||
| 24 | Assert.Null(hash.Exception); | ||
| 25 | } | ||
| 26 | |||
| 27 | [Fact] | ||
| 28 | public void CannotGetHashesFromUnsignedFile() | ||
| 29 | { | ||
| 30 | var txtFile = TestData.Get(@"TestData\test.txt"); | ||
| 31 | |||
| 32 | var hashes = CertificateHashes.Read(new[] { txtFile }); | ||
| 33 | |||
| 34 | var hash = hashes.Single(); | ||
| 35 | Assert.Equal(txtFile, hash.Path); | ||
| 36 | Assert.Null(hash.Exception); | ||
| 37 | } | ||
| 38 | |||
| 39 | [Fact] | ||
| 40 | public void CanGetMultipleHashes() | ||
| 41 | { | ||
| 42 | var cabFile = TestData.Get(@"TestData\test.cab"); | ||
| 43 | var txtFile = TestData.Get(@"TestData\test.txt"); | ||
| 44 | |||
| 45 | var hashes = CertificateHashes.Read(new[] { cabFile, txtFile }); | ||
| 46 | |||
| 47 | Assert.Equal(cabFile, hashes[0].Path); | ||
| 48 | Assert.Equal("7EC90B3FC3D580EB571210011F1095E149DCC6BB", hashes[0].PublicKey); | ||
| 49 | Assert.Equal("0B13494DB50BC185A34389BBBAA01EDD1CF56350", hashes[0].Thumbprint); | ||
| 50 | Assert.Null(hashes[0].Exception); | ||
| 51 | |||
| 52 | Assert.Equal(txtFile, hashes[1].Path); | ||
| 53 | Assert.Empty(hashes[1].PublicKey); | ||
| 54 | Assert.Empty(hashes[1].Thumbprint); | ||
| 55 | Assert.Null(hashes[1].Exception); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
diff --git a/src/wix/test/WixToolsetTest.Core.Native/TestData/test.cab b/src/wix/test/WixToolsetTest.Core.Native/TestData/test.cab index ca78f632..9700cd64 100644 --- a/src/wix/test/WixToolsetTest.Core.Native/TestData/test.cab +++ b/src/wix/test/WixToolsetTest.Core.Native/TestData/test.cab | |||
| Binary files differ | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs index 6b2d8bfa..5d0c8561 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs | |||
| @@ -57,6 +57,26 @@ namespace WixToolsetTest.CoreIntegration | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | [Fact] | 59 | [Fact] |
| 60 | public void CanSpecifyPackagePayloadWithCertificate() | ||
| 61 | { | ||
| 62 | var folder = TestData.Get(@"TestData", "PackagePayload"); | ||
| 63 | |||
| 64 | using (var fs = new DisposableFileSystem()) | ||
| 65 | { | ||
| 66 | var baseFolder = fs.GetFolder(); | ||
| 67 | |||
| 68 | var result = WixRunner.Execute(new[] | ||
| 69 | { | ||
| 70 | "build", | ||
| 71 | Path.Combine(folder, "SpecifiedCertificate.wxs"), | ||
| 72 | "-o", Path.Combine(baseFolder, "test.wixlib") | ||
| 73 | }); | ||
| 74 | |||
| 75 | result.AssertSuccess(); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | [Fact] | ||
| 60 | public void ErrorWhenMissingSourceFileAndHash() | 80 | public void ErrorWhenMissingSourceFileAndHash() |
| 61 | { | 81 | { |
| 62 | var folder = TestData.Get(@"TestData", "PackagePayload"); | 82 | var folder = TestData.Get(@"TestData", "PackagePayload"); |
| @@ -75,7 +95,7 @@ namespace WixToolsetTest.CoreIntegration | |||
| 75 | Assert.Equal(44, result.ExitCode); | 95 | Assert.Equal(44, result.ExitCode); |
| 76 | WixAssert.CompareLineByLine(new[] | 96 | WixAssert.CompareLineByLine(new[] |
| 77 | { | 97 | { |
| 78 | "The MsuPackagePayload element's SourceFile or Hash attribute was not found; one of these is required.", | 98 | "The MsuPackagePayload element's SourceFile, CertificatePublicKey, or Hash attribute was not found; one of these is required.", |
| 79 | }, result.Messages.Select(m => m.ToString()).ToArray()); | 99 | }, result.Messages.Select(m => m.ToString()).ToArray()); |
| 80 | } | 100 | } |
| 81 | } | 101 | } |
| @@ -144,10 +164,10 @@ namespace WixToolsetTest.CoreIntegration | |||
| 144 | "-o", Path.Combine(baseFolder, "test.wixlib") | 164 | "-o", Path.Combine(baseFolder, "test.wixlib") |
| 145 | }); | 165 | }); |
| 146 | 166 | ||
| 147 | Assert.Equal(10, result.ExitCode); | 167 | Assert.Equal(408, result.ExitCode); |
| 148 | WixAssert.CompareLineByLine(new[] | 168 | WixAssert.CompareLineByLine(new[] |
| 149 | { | 169 | { |
| 150 | "The MsuPackagePayload/@DownloadUrl attribute was not found; it is required when attribute Hash is specified.", | 170 | "The MsuPackagePayload element's DownloadUrl attribute was not found; it is required without attribute SourceFile present.", |
| 151 | }, result.Messages.Select(m => m.ToString()).ToArray()); | 171 | }, result.Messages.Select(m => m.ToString()).ToArray()); |
| 152 | } | 172 | } |
| 153 | } | 173 | } |
| @@ -177,6 +197,102 @@ namespace WixToolsetTest.CoreIntegration | |||
| 177 | } | 197 | } |
| 178 | 198 | ||
| 179 | [Fact] | 199 | [Fact] |
| 200 | public void ErrorWhenSpecifiedSourceFileAndCertificatePublicKey() | ||
| 201 | { | ||
| 202 | var folder = TestData.Get(@"TestData", "PackagePayload"); | ||
| 203 | |||
| 204 | using (var fs = new DisposableFileSystem()) | ||
| 205 | { | ||
| 206 | var baseFolder = fs.GetFolder(); | ||
| 207 | |||
| 208 | var result = WixRunner.Execute(new[] | ||
| 209 | { | ||
| 210 | "build", | ||
| 211 | Path.Combine(folder, "SpecifiedSourceFileAndCertificatePublicKey.wxs"), | ||
| 212 | "-o", Path.Combine(baseFolder, "test.wixlib") | ||
| 213 | }); | ||
| 214 | |||
| 215 | WixAssert.CompareLineByLine(new[] | ||
| 216 | { | ||
| 217 | "The ExePackagePayload/@CertificatePublicKey attribute cannot be specified when attribute SourceFile is present.", | ||
| 218 | }, result.Messages.Select(m => m.ToString()).ToArray()); | ||
| 219 | Assert.Equal(35, result.ExitCode); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | [Fact] | ||
| 224 | public void ErrorWhenSpecifiedSourceFileAndCertificateThumprint() | ||
| 225 | { | ||
| 226 | var folder = TestData.Get(@"TestData", "PackagePayload"); | ||
| 227 | |||
| 228 | using (var fs = new DisposableFileSystem()) | ||
| 229 | { | ||
| 230 | var baseFolder = fs.GetFolder(); | ||
| 231 | |||
| 232 | var result = WixRunner.Execute(new[] | ||
| 233 | { | ||
| 234 | "build", | ||
| 235 | Path.Combine(folder, "SpecifiedSourceFileAndCertificateThumbprint.wxs"), | ||
| 236 | "-o", Path.Combine(baseFolder, "test.wixlib") | ||
| 237 | }); | ||
| 238 | |||
| 239 | WixAssert.CompareLineByLine(new[] | ||
| 240 | { | ||
| 241 | "The ExePackagePayload/@CertificateThumbprint attribute cannot be specified when attribute SourceFile is present.", | ||
| 242 | }, result.Messages.Select(m => m.ToString()).ToArray()); | ||
| 243 | Assert.Equal(35, result.ExitCode); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | [Fact] | ||
| 248 | public void ErrorWhenSpecifiedCertificateThumbprintWithoutPublicKey() | ||
| 249 | { | ||
| 250 | var folder = TestData.Get(@"TestData", "PackagePayload"); | ||
| 251 | |||
| 252 | using (var fs = new DisposableFileSystem()) | ||
| 253 | { | ||
| 254 | var baseFolder = fs.GetFolder(); | ||
| 255 | |||
| 256 | var result = WixRunner.Execute(new[] | ||
| 257 | { | ||
| 258 | "build", | ||
| 259 | Path.Combine(folder, "SpecifiedHashAndCertificatePublicKey.wxs"), | ||
| 260 | "-o", Path.Combine(baseFolder, "test.wixlib") | ||
| 261 | }); | ||
| 262 | |||
| 263 | WixAssert.CompareLineByLine(new[] | ||
| 264 | { | ||
| 265 | "The ExePackagePayload/@CertificatePublicKey attribute was not found; it is required when attribute CertificateThumbprint is specified.", | ||
| 266 | }, result.Messages.Select(m => m.ToString()).ToArray()); | ||
| 267 | Assert.Equal(10, result.ExitCode); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | [Fact] | ||
| 272 | public void ErrorWhenSpecifiedCertificatePublicKeyWithoutThumbprint() | ||
| 273 | { | ||
| 274 | var folder = TestData.Get(@"TestData", "PackagePayload"); | ||
| 275 | |||
| 276 | using (var fs = new DisposableFileSystem()) | ||
| 277 | { | ||
| 278 | var baseFolder = fs.GetFolder(); | ||
| 279 | |||
| 280 | var result = WixRunner.Execute(new[] | ||
| 281 | { | ||
| 282 | "build", | ||
| 283 | Path.Combine(folder, "SpecifiedCertificatePublicKeyWithoutThumbprint.wxs"), | ||
| 284 | "-o", Path.Combine(baseFolder, "test.wixlib") | ||
| 285 | }); | ||
| 286 | |||
| 287 | WixAssert.CompareLineByLine(new[] | ||
| 288 | { | ||
| 289 | "The ExePackagePayload/@CertificateThumbprint attribute was not found; it is required when attribute CertificatePublicKey is specified.", | ||
| 290 | }, result.Messages.Select(m => m.ToString()).ToArray()); | ||
| 291 | Assert.Equal(10, result.ExitCode); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | [Fact] | ||
| 180 | public void ErrorWhenWrongPackagePayloadInPayloadGroup() | 296 | public void ErrorWhenWrongPackagePayloadInPayloadGroup() |
| 181 | { | 297 | { |
| 182 | var folder = TestData.Get(@"TestData"); | 298 | var folder = TestData.Get(@"TestData"); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs new file mode 100644 index 00000000..434b3621 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.CoreIntegration | ||
| 4 | { | ||
| 5 | using System.IO; | ||
| 6 | using System.Linq; | ||
| 7 | using WixBuildTools.TestSupport; | ||
| 8 | using WixToolset.Core.TestPackage; | ||
| 9 | using Xunit; | ||
| 10 | |||
| 11 | public class RemotePayloadFixture | ||
| 12 | { | ||
| 13 | [Fact] | ||
| 14 | public void CanGetRemotePayload() | ||
| 15 | { | ||
| 16 | var folder = TestData.Get(@"TestData"); | ||
| 17 | |||
| 18 | using (var fs = new DisposableFileSystem()) | ||
| 19 | { | ||
| 20 | var outputFolder = fs.GetFolder(); | ||
| 21 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
| 22 | |||
| 23 | var result = WixRunner.Execute(new[] | ||
| 24 | { | ||
| 25 | "burn", "remotepayload", | ||
| 26 | Path.Combine(folder, ".Data", "burn.exe"), | ||
| 27 | "-downloadurl", "https://www.example.com/files/{0}", | ||
| 28 | "-o", outFile | ||
| 29 | }); | ||
| 30 | |||
| 31 | result.AssertSuccess(); | ||
| 32 | |||
| 33 | var elements = File.ReadAllLines(outFile); | ||
| 34 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
| 35 | |||
| 36 | WixAssert.CompareLineByLine(new[] | ||
| 37 | { | ||
| 38 | @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />", | ||
| 39 | }, elements); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | [Fact] | ||
| 44 | public void CanGetRemoteMsuPayload() | ||
| 45 | { | ||
| 46 | var folder = TestData.Get(@"TestData"); | ||
| 47 | |||
| 48 | using (var fs = new DisposableFileSystem()) | ||
| 49 | { | ||
| 50 | var outputFolder = fs.GetFolder(); | ||
| 51 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
| 52 | |||
| 53 | var result = WixRunner.Execute(new[] | ||
| 54 | { | ||
| 55 | "burn", "remotepayload", | ||
| 56 | Path.Combine(folder, ".Data", "Windows8.1-KB2937592-x86.msu"), | ||
| 57 | "-o", outFile | ||
| 58 | }); | ||
| 59 | |||
| 60 | result.AssertSuccess(); | ||
| 61 | |||
| 62 | var elements = File.ReadAllLines(outFile); | ||
| 63 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
| 64 | |||
| 65 | WixAssert.CompareLineByLine(new[] | ||
| 66 | { | ||
| 67 | @"<MsuPackagePayload Name='Windows8.1-KB2937592-x86.msu' Hash='904ADEA6AB675ACE16483138BF3F5850FD56ACB6E3A13AFA7263ED49C68CCE6CF84D6AAD6F99AAF175A95EE1A56C787C5AD968019056490B1073E7DBB7B9B7BE' Size='309544' />", | ||
| 68 | }, elements); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | [Fact] | ||
| 73 | public void CanGetRemotePayloadWithCertificate() | ||
| 74 | { | ||
| 75 | var folder = TestData.Get(@"TestData"); | ||
| 76 | |||
| 77 | using (var fs = new DisposableFileSystem()) | ||
| 78 | { | ||
| 79 | var outputFolder = fs.GetFolder(); | ||
| 80 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
| 81 | |||
| 82 | var result = WixRunner.Execute(new[] | ||
| 83 | { | ||
| 84 | "burn", "remotepayload", | ||
| 85 | "-usecertificate", | ||
| 86 | Path.Combine(folder, ".Data", "burn.exe"), | ||
| 87 | Path.Combine(folder, ".Data", "signed_cab1.cab"), | ||
| 88 | "-o", outFile | ||
| 89 | }); | ||
| 90 | |||
| 91 | result.AssertSuccess(); | ||
| 92 | |||
| 93 | var elements = File.ReadAllLines(outFile); | ||
| 94 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
| 95 | |||
| 96 | WixAssert.CompareLineByLine(new[] | ||
| 97 | { | ||
| 98 | @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />", | ||
| 99 | @"<Payload Name='signed_cab1.cab' CertificatePublicKey='BBD1B48A37503767C71F455624967D406A5D66C3' CertificateThumbprint='DE13B4CE635E3F63AA2394E66F95C460267BC82F' Hash='D8D3842403710E1F6036A62543224855CADF546853933C2B17BA99D789D4347B36717687C022678A9D3DE749DFC1482DAAB92B997B62BB32A8A6828B9D04C414' Size='1585' />", | ||
| 100 | }, elements); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | [Fact] | ||
| 105 | public void CanGetRemotePayloadWithoutCertificate() | ||
| 106 | { | ||
| 107 | var folder = TestData.Get(@"TestData"); | ||
| 108 | |||
| 109 | using (var fs = new DisposableFileSystem()) | ||
| 110 | { | ||
| 111 | var outputFolder = fs.GetFolder(); | ||
| 112 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
| 113 | |||
| 114 | var result = WixRunner.Execute(new[] | ||
| 115 | { | ||
| 116 | "burn", "remotepayload", | ||
| 117 | Path.Combine(folder, ".Data", "burn.exe"), | ||
| 118 | Path.Combine(folder, ".Data", "signed_cab1.cab"), | ||
| 119 | "-o", outFile | ||
| 120 | }); | ||
| 121 | |||
| 122 | result.AssertSuccess(); | ||
| 123 | |||
| 124 | var elements = File.ReadAllLines(outFile); | ||
| 125 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
| 126 | |||
| 127 | WixAssert.CompareLineByLine(new[] | ||
| 128 | { | ||
| 129 | @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />", | ||
| 130 | @"<Payload Name='signed_cab1.cab' Hash='D8D3842403710E1F6036A62543224855CADF546853933C2B17BA99D789D4347B36717687C022678A9D3DE749DFC1482DAAB92B997B62BB32A8A6828B9D04C414' Size='1585' />", | ||
| 131 | }, elements); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | [Fact] | ||
| 136 | public void CanGetRemotePayloadsRecursive() | ||
| 137 | { | ||
| 138 | var folder = TestData.Get(@"TestData"); | ||
| 139 | |||
| 140 | using (var fs = new DisposableFileSystem()) | ||
| 141 | { | ||
| 142 | var outputFolder = fs.GetFolder(); | ||
| 143 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
| 144 | |||
| 145 | var result = WixRunner.Execute(new[] | ||
| 146 | { | ||
| 147 | "burn", "remotepayload", | ||
| 148 | "-recurse", | ||
| 149 | "-du", "https://www.example.com/files/{0}", | ||
| 150 | Path.Combine(folder, ".Data", "burn.exe"), | ||
| 151 | Path.Combine(folder, "RemotePayload", "*"), | ||
| 152 | "-basepath", folder, | ||
| 153 | "-bp", Path.Combine(folder, ".Data"), | ||
| 154 | "-o", outFile | ||
| 155 | }); | ||
| 156 | |||
| 157 | result.AssertSuccess(); | ||
| 158 | |||
| 159 | var elements = File.ReadAllLines(outFile); | ||
| 160 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
| 161 | |||
| 162 | WixAssert.CompareLineByLine(new[] | ||
| 163 | { | ||
| 164 | @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />", | ||
| 165 | @"<Payload Name='a.dat' DownloadUrl='https://www.example.com/files/RemotePayload/a.dat' Hash='D13926E5CBE5ED8B46133F9199FAF2FF25B25981C67A31AE2BC3F6C20390FACBFADCD89BD22D3445D95B989C8EACFB1E68DB634BECB5C9624865BA453BCE362A' Size='16' />", | ||
| 166 | @"<Payload Name='b.dat' DownloadUrl='https://www.example.com/files/RemotePayload/subfolder/b.dat' Hash='5F94707BC29ADFE3B9615E6753388707FD0B8F5FD9EEEC2B17E21E72F1635FF7D7A101E7D14F614E111F263CB9AC4D0940BE1247881A7844F226D6C400293D8E' Size='37' />", | ||
| 167 | @"<Payload Name='c.dat' DownloadUrl='https://www.example.com/files/RemotePayload/subfolder/c.dat' Hash='97D6209A5571E05E4F72F9C6BF0987651FA03E63F971F9B53C2B3D798A666D9864F232D4E2D6442E47D9D72B282309B6EEFF4EE017B43B706FA92A0F5EF74734' Size='42' />", | ||
| 168 | }, elements); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } | ||
diff --git a/src/wix/test/WixToolsetTest.Heat/TestData/.Data/Windows8.1-KB2937592-x86.msu b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/Windows8.1-KB2937592-x86.msu index c39f53b0..c39f53b0 100644 --- a/src/wix/test/WixToolsetTest.Heat/TestData/.Data/Windows8.1-KB2937592-x86.msu +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/Windows8.1-KB2937592-x86.msu | |||
| Binary files differ | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs new file mode 100644 index 00000000..b5dec9a2 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <PackageGroup Id="BundlePackages"> | ||
| 5 | <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none"> | ||
| 6 | <ExePackagePayload CertificatePublicKey="abcd" CertificateThumbprint="abcd" Hash="1234" DownloadUrl="https://example.com/" Name="fake.exe" Size="100" /> | ||
| 7 | </ExePackage> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs new file mode 100644 index 00000000..aa915a31 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <PackageGroup Id="BundlePackages"> | ||
| 5 | <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none"> | ||
| 6 | <ExePackagePayload CertificatePublicKey="abcd" Hash="123" DownloadUrl="https://example.com/" Name="fake.exe" Size="100" /> | ||
| 7 | </ExePackage> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndCertificatePublicKey.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndCertificatePublicKey.wxs new file mode 100644 index 00000000..5570017e --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndCertificatePublicKey.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <PackageGroup Id="BundlePackages"> | ||
| 5 | <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none"> | ||
| 6 | <ExePackagePayload Hash="abcd" CertificateThumbprint="abcd" DownloadUrl="https://example.com/" Name="fake.exe" Size="100" /> | ||
| 7 | </ExePackage> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificatePublicKey.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificatePublicKey.wxs new file mode 100644 index 00000000..b79b5596 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificatePublicKey.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <PackageGroup Id="BundlePackages"> | ||
| 5 | <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none"> | ||
| 6 | <ExePackagePayload SourceFile="example.exe" CertificatePublicKey="abcd" /> | ||
| 7 | </ExePackage> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificateThumbprint.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificateThumbprint.wxs new file mode 100644 index 00000000..ad2ab521 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndCertificateThumbprint.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <PackageGroup Id="BundlePackages"> | ||
| 5 | <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none"> | ||
| 6 | <ExePackagePayload SourceFile="example.exe" CertificateThumbprint="abcd" /> | ||
| 7 | </ExePackage> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/a.dat b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/a.dat new file mode 100644 index 00000000..a96b19b3 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/a.dat | |||
| @@ -0,0 +1 @@ | |||
| This is a.dat. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/b.dat b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/b.dat new file mode 100644 index 00000000..35c4c043 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/b.dat | |||
| @@ -0,0 +1 @@ | |||
| This is b.dat. A little bit longer. | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/c.dat b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/c.dat new file mode 100644 index 00000000..937aa91f --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/subfolder/c.dat | |||
| @@ -0,0 +1 @@ | |||
| This is c.dat. A little bit longer, now! | |||
diff --git a/src/wix/test/WixToolsetTest.Heat/PayloadTests.cs b/src/wix/test/WixToolsetTest.Heat/PayloadTests.cs deleted file mode 100644 index 8072f50d..00000000 --- a/src/wix/test/WixToolsetTest.Heat/PayloadTests.cs +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.Harvesters | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using WixBuildTools.TestSupport; | ||
| 8 | using Xunit; | ||
| 9 | |||
| 10 | public class PayloadTests | ||
| 11 | { | ||
| 12 | [Fact] | ||
| 13 | public void CanHarvestExePackagePayload() | ||
| 14 | { | ||
| 15 | var folder = TestData.Get(@"TestData"); | ||
| 16 | |||
| 17 | using (var fs = new DisposableFileSystem()) | ||
| 18 | { | ||
| 19 | var baseFolder = fs.GetFolder(); | ||
| 20 | var outputFilePath = Path.Combine(baseFolder, "test.wxs"); | ||
| 21 | |||
| 22 | var result = HeatRunner.Execute(new[] | ||
| 23 | { | ||
| 24 | "exepackagepayload", | ||
| 25 | Path.Combine(folder, ".Data", "burn.exe"), | ||
| 26 | "-o", outputFilePath, | ||
| 27 | }); | ||
| 28 | |||
| 29 | result.AssertSuccess(); | ||
| 30 | |||
| 31 | Assert.True(File.Exists(outputFilePath)); | ||
| 32 | |||
| 33 | var expected = File.ReadAllText(Path.Combine(folder, "Payload", "HarvestedExePackagePayload.wxs")).Replace("\r\n", "\n"); | ||
| 34 | var actual = File.ReadAllText(outputFilePath).Replace("\r\n", "\n"); | ||
| 35 | Assert.Equal(expected, actual); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | [Fact] | ||
| 40 | public void CanHarvestMsuPackagePayload() | ||
| 41 | { | ||
| 42 | var folder = TestData.Get(@"TestData"); | ||
| 43 | |||
| 44 | using (var fs = new DisposableFileSystem()) | ||
| 45 | { | ||
| 46 | var baseFolder = fs.GetFolder(); | ||
| 47 | var outputFilePath = Path.Combine(baseFolder, "test.wxs"); | ||
| 48 | |||
| 49 | var result = HeatRunner.Execute(new[] | ||
| 50 | { | ||
| 51 | "msupackagepayload", | ||
| 52 | Path.Combine(folder, ".Data", "Windows8.1-KB2937592-x86.msu"), | ||
| 53 | "-o", outputFilePath, | ||
| 54 | }); | ||
| 55 | |||
| 56 | result.AssertSuccess(); | ||
| 57 | |||
| 58 | Assert.True(File.Exists(outputFilePath)); | ||
| 59 | |||
| 60 | var expected = File.ReadAllText(Path.Combine(folder, "Payload", "HarvestedMsuPackagePayload.wxs")).Replace("\r\n", "\n"); | ||
| 61 | var actual = File.ReadAllText(outputFilePath).Replace("\r\n", "\n"); | ||
| 62 | Assert.Equal(expected, actual); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
diff --git a/src/wix/test/WixToolsetTest.Heat/TestData/.Data/burn.exe b/src/wix/test/WixToolsetTest.Heat/TestData/.Data/burn.exe deleted file mode 100644 index 2a4f423f..00000000 --- a/src/wix/test/WixToolsetTest.Heat/TestData/.Data/burn.exe +++ /dev/null | |||
| Binary files differ | |||
diff --git a/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedExePackagePayload.wxs b/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedExePackagePayload.wxs deleted file mode 100644 index 40100f22..00000000 --- a/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedExePackagePayload.wxs +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <ExePackagePayload Description="WiX Toolset Bootstrapper" Hash="F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E" ProductName="Windows Installer XML Toolset" Size="463360" Version="3.14.1703.0" /> | ||
| 5 | </Fragment> | ||
| 6 | </Wix> \ No newline at end of file | ||
diff --git a/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedMsuPackagePayload.wxs b/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedMsuPackagePayload.wxs deleted file mode 100644 index f203fe27..00000000 --- a/src/wix/test/WixToolsetTest.Heat/TestData/Payload/HarvestedMsuPackagePayload.wxs +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <MsuPackagePayload Hash="904ADEA6AB675ACE16483138BF3F5850FD56ACB6E3A13AFA7263ED49C68CCE6CF84D6AAD6F99AAF175A95EE1A56C787C5AD968019056490B1073E7DBB7B9B7BE" Size="309544" /> | ||
| 5 | </Fragment> | ||
| 6 | </Wix> \ No newline at end of file | ||
diff --git a/src/wix/test/WixToolsetTest.Heat/WixToolsetTest.Heat.csproj b/src/wix/test/WixToolsetTest.Heat/WixToolsetTest.Heat.csproj index 2a706aa0..1ba62393 100644 --- a/src/wix/test/WixToolsetTest.Heat/WixToolsetTest.Heat.csproj +++ b/src/wix/test/WixToolsetTest.Heat/WixToolsetTest.Heat.csproj | |||
| @@ -9,10 +9,6 @@ | |||
| 9 | </PropertyGroup> | 9 | </PropertyGroup> |
| 10 | 10 | ||
| 11 | <ItemGroup> | 11 | <ItemGroup> |
| 12 | <Content Include="TestData\**" CopyToOutputDirectory="PreserveNewest" /> | ||
| 13 | </ItemGroup> | ||
| 14 | |||
| 15 | <ItemGroup> | ||
| 16 | <ProjectReference Include="..\..\heat\heat.csproj" /> | 12 | <ProjectReference Include="..\..\heat\heat.csproj" /> |
| 17 | <ProjectReference Include="..\..\WixToolset.Core.TestPackage\WixToolset.Core.TestPackage.csproj" /> | 13 | <ProjectReference Include="..\..\WixToolset.Core.TestPackage\WixToolset.Core.TestPackage.csproj" /> |
| 18 | </ItemGroup> | 14 | </ItemGroup> |
diff --git a/src/wix/wixnative/certhashes.cpp b/src/wix/wixnative/certhashes.cpp new file mode 100644 index 00000000..cbb548ba --- /dev/null +++ b/src/wix/wixnative/certhashes.cpp | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | #define SHA1_HASH_LEN 20 | ||
| 6 | |||
| 7 | static HRESULT GetPublicKeyIdentifierAndThumbprint( | ||
| 8 | __in_z LPCWSTR wzPath, | ||
| 9 | __inout_z LPWSTR* psczPublicKeyIdentifier, | ||
| 10 | __inout_z LPWSTR* psczThumbprint); | ||
| 11 | |||
| 12 | static HRESULT GetChainContext( | ||
| 13 | __in_z LPCWSTR wzPath, | ||
| 14 | __out PCCERT_CHAIN_CONTEXT* ppChainContext); | ||
| 15 | |||
| 16 | |||
| 17 | HRESULT CertificateHashesCommand( | ||
| 18 | __in int argc, | ||
| 19 | __in_ecount(argc) LPWSTR argv[]) | ||
| 20 | { | ||
| 21 | Unused(argc); | ||
| 22 | Unused(argv); | ||
| 23 | |||
| 24 | HRESULT hr = S_OK; | ||
| 25 | |||
| 26 | LPWSTR sczFilePath = NULL; | ||
| 27 | LPWSTR sczPublicKeyIdentifier = NULL; | ||
| 28 | LPWSTR sczThumbprint = NULL; | ||
| 29 | |||
| 30 | hr = WixNativeReadStdinPreamble(); | ||
| 31 | ExitOnFailure(hr, "Failed to read stdin preamble before reading paths to get certificate hashes"); | ||
| 32 | |||
| 33 | // Get the hash for each provided file. | ||
| 34 | for (;;) | ||
| 35 | { | ||
| 36 | hr = ConsoleReadW(&sczFilePath); | ||
| 37 | ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to read file path to signed file from stdin"); | ||
| 38 | |||
| 39 | if (!*sczFilePath) | ||
| 40 | { | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | |||
| 44 | hr = GetPublicKeyIdentifierAndThumbprint(sczFilePath, &sczPublicKeyIdentifier, &sczThumbprint); | ||
| 45 | if (FAILED(hr)) | ||
| 46 | { | ||
| 47 | // Treat no signature as success without finding certificate hashes. | ||
| 48 | ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls\t\t\t0x%x", sczFilePath, TRUST_E_NOSIGNATURE == hr ? 0 : hr); | ||
| 49 | } | ||
| 50 | else | ||
| 51 | { | ||
| 52 | ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls\t%ls\t%ls\t0x%x", sczFilePath, sczPublicKeyIdentifier, sczThumbprint, hr); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | LExit: | ||
| 57 | ReleaseStr(sczThumbprint); | ||
| 58 | ReleaseStr(sczPublicKeyIdentifier); | ||
| 59 | ReleaseStr(sczFilePath); | ||
| 60 | |||
| 61 | return hr; | ||
| 62 | } | ||
| 63 | |||
| 64 | static HRESULT GetPublicKeyIdentifierAndThumbprint( | ||
| 65 | __in_z LPCWSTR wzPath, | ||
| 66 | __inout_z LPWSTR* psczPublicKeyIdentifier, | ||
| 67 | __inout_z LPWSTR* psczThumbprint) | ||
| 68 | { | ||
| 69 | HRESULT hr = S_OK; | ||
| 70 | PCCERT_CHAIN_CONTEXT pChainContext = NULL; | ||
| 71 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 72 | BYTE rgbPublicKeyIdentifier[SHA1_HASH_LEN] = { }; | ||
| 73 | DWORD cbPublicKeyIdentifier = sizeof(rgbPublicKeyIdentifier); | ||
| 74 | BYTE* pbThumbprint = NULL; | ||
| 75 | DWORD cbThumbprint = 0; | ||
| 76 | |||
| 77 | hr = GetChainContext(wzPath, &pChainContext); | ||
| 78 | ExitOnFailure(hr, "Failed to get chain context for file: %ls", wzPath); | ||
| 79 | |||
| 80 | pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; | ||
| 81 | |||
| 82 | // Get the certificate's public key identifier and thumbprint. | ||
| 83 | if (!::CryptHashPublicKeyInfo(NULL, CALG_SHA1, 0, X509_ASN_ENCODING, &pCertContext->pCertInfo->SubjectPublicKeyInfo, rgbPublicKeyIdentifier, &cbPublicKeyIdentifier)) | ||
| 84 | { | ||
| 85 | ExitWithLastError(hr, "Failed to get certificate public key identifier from file: %ls", wzPath); | ||
| 86 | } | ||
| 87 | |||
| 88 | hr = CertReadProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, &pbThumbprint, &cbThumbprint); | ||
| 89 | ExitOnFailure(hr, "Failed to read certificate thumbprint from file: %ls", wzPath); | ||
| 90 | |||
| 91 | // Get the public key indentifier and thumbprint in hex. | ||
| 92 | hr = StrAllocHexEncode(rgbPublicKeyIdentifier, cbPublicKeyIdentifier, psczPublicKeyIdentifier); | ||
| 93 | ExitOnFailure(hr, "Failed to convert certificate public key to hex for file: %ls", wzPath); | ||
| 94 | |||
| 95 | hr = StrAllocHexEncode(pbThumbprint, cbThumbprint, psczThumbprint); | ||
| 96 | ExitOnFailure(hr, "Failed to convert certificate thumbprint to hex for file: %ls", wzPath); | ||
| 97 | |||
| 98 | LExit: | ||
| 99 | ReleaseMem(pbThumbprint); | ||
| 100 | return hr; | ||
| 101 | } | ||
| 102 | |||
| 103 | static HRESULT GetChainContext( | ||
| 104 | __in_z LPCWSTR wzPath, | ||
| 105 | __out PCCERT_CHAIN_CONTEXT* ppChainContext) | ||
| 106 | { | ||
| 107 | HRESULT hr = S_OK; | ||
| 108 | |||
| 109 | GUID guidAuthenticode = WINTRUST_ACTION_GENERIC_VERIFY_V2; | ||
| 110 | WINTRUST_FILE_INFO wfi = { }; | ||
| 111 | WINTRUST_DATA wtd = { }; | ||
| 112 | CRYPT_PROVIDER_DATA* pProviderData = NULL; | ||
| 113 | CRYPT_PROVIDER_SGNR* pSigner = NULL; | ||
| 114 | |||
| 115 | wfi.cbStruct = sizeof(wfi); | ||
| 116 | wfi.pcwszFilePath = wzPath; | ||
| 117 | |||
| 118 | wtd.cbStruct = sizeof(wtd); | ||
| 119 | wtd.dwUnionChoice = WTD_CHOICE_FILE; | ||
| 120 | wtd.pFile = &wfi; | ||
| 121 | wtd.dwStateAction = WTD_STATEACTION_VERIFY; | ||
| 122 | wtd.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_HASH_ONLY_FLAG | WTD_CACHE_ONLY_URL_RETRIEVAL; | ||
| 123 | wtd.dwUIChoice = WTD_UI_NONE; | ||
| 124 | |||
| 125 | hr = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd); | ||
| 126 | ExitOnFailure(hr, "Failed to verify certificate on file: %ls", wzPath); | ||
| 127 | |||
| 128 | pProviderData = ::WTHelperProvDataFromStateData(wtd.hWVTStateData); | ||
| 129 | ExitOnNullWithLastError(pProviderData, hr, "Failed to get provider state from authenticode certificate on file: %ls", wzPath); | ||
| 130 | |||
| 131 | pSigner = ::WTHelperGetProvSignerFromChain(pProviderData, 0, FALSE, 0); | ||
| 132 | ExitOnNullWithLastError(pSigner, hr, "Failed to get signer chain from authenticode certificate on file: %ls", wzPath); | ||
| 133 | |||
| 134 | *ppChainContext = pSigner->pChainContext; | ||
| 135 | |||
| 136 | LExit: | ||
| 137 | return hr; | ||
| 138 | } | ||
diff --git a/src/wix/wixnative/precomp.h b/src/wix/wixnative/precomp.h index 490bbdcf..0a458ca6 100644 --- a/src/wix/wixnative/precomp.h +++ b/src/wix/wixnative/precomp.h | |||
| @@ -4,9 +4,12 @@ | |||
| 4 | #include <windows.h> | 4 | #include <windows.h> |
| 5 | #include <aclapi.h> | 5 | #include <aclapi.h> |
| 6 | #include <mergemod.h> | 6 | #include <mergemod.h> |
| 7 | #include <softpub.h> | ||
| 7 | #include <strsafe.h> | 8 | #include <strsafe.h> |
| 9 | #include <wintrust.h> | ||
| 8 | 10 | ||
| 9 | #include "dutil.h" | 11 | #include "dutil.h" |
| 12 | #include "certutil.h" | ||
| 10 | #include "conutil.h" | 13 | #include "conutil.h" |
| 11 | #include "memutil.h" | 14 | #include "memutil.h" |
| 12 | #include "pathutil.h" | 15 | #include "pathutil.h" |
| @@ -15,6 +18,7 @@ | |||
| 15 | #include "cabutil.h" | 18 | #include "cabutil.h" |
| 16 | 19 | ||
| 17 | HRESULT WixNativeReadStdinPreamble(); | 20 | HRESULT WixNativeReadStdinPreamble(); |
| 21 | HRESULT CertificateHashesCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); | ||
| 18 | HRESULT SmartCabCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); | 22 | HRESULT SmartCabCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); |
| 19 | HRESULT ResetAclsCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); | 23 | HRESULT ResetAclsCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); |
| 20 | HRESULT EnumCabCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); | 24 | HRESULT EnumCabCommand(__in int argc, __in_ecount(argc) LPWSTR argv[]); |
diff --git a/src/wix/wixnative/wixnative.cpp b/src/wix/wixnative/wixnative.cpp index d1236da1..8a24d5f1 100644 --- a/src/wix/wixnative/wixnative.cpp +++ b/src/wix/wixnative/wixnative.cpp | |||
| @@ -24,6 +24,10 @@ int __cdecl wmain(int argc, LPWSTR argv[]) | |||
| 24 | { | 24 | { |
| 25 | hr = EnumCabCommand(argc - 2, argv + 2); | 25 | hr = EnumCabCommand(argc - 2, argv + 2); |
| 26 | } | 26 | } |
| 27 | else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"certhashes", -1)) | ||
| 28 | { | ||
| 29 | hr = CertificateHashesCommand(argc - 2, argv + 2); | ||
| 30 | } | ||
| 27 | else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"resetacls", -1)) | 31 | else if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"resetacls", -1)) |
| 28 | { | 32 | { |
| 29 | hr = ResetAclsCommand(argc - 2, argv + 2); | 33 | hr = ResetAclsCommand(argc - 2, argv + 2); |
diff --git a/src/wix/wixnative/wixnative.vcxproj b/src/wix/wixnative/wixnative.vcxproj index 1dac36e2..2e90661c 100644 --- a/src/wix/wixnative/wixnative.vcxproj +++ b/src/wix/wixnative/wixnative.vcxproj | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | 42 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 43 | 43 | ||
| 44 | <PropertyGroup> | 44 | <PropertyGroup> |
| 45 | <ProjectAdditionalLinkLibraries>crypt32.lib;cabinet.lib;msi.lib</ProjectAdditionalLinkLibraries> | 45 | <ProjectAdditionalLinkLibraries>crypt32.lib;cabinet.lib;msi.lib;wintrust.lib</ProjectAdditionalLinkLibraries> |
| 46 | </PropertyGroup> | 46 | </PropertyGroup> |
| 47 | 47 | ||
| 48 | <ItemGroup> | 48 | <ItemGroup> |
| @@ -50,6 +50,7 @@ | |||
| 50 | <ClCompile Include="precomp.cpp"> | 50 | <ClCompile Include="precomp.cpp"> |
| 51 | <PrecompiledHeader>Create</PrecompiledHeader> | 51 | <PrecompiledHeader>Create</PrecompiledHeader> |
| 52 | </ClCompile> | 52 | </ClCompile> |
| 53 | <ClCompile Include="certhashes.cpp" /> | ||
| 53 | <ClCompile Include="enumcab.cpp" /> | 54 | <ClCompile Include="enumcab.cpp" /> |
| 54 | <ClCompile Include="extractcab.cpp" /> | 55 | <ClCompile Include="extractcab.cpp" /> |
| 55 | <ClCompile Include="resetacls.cpp" /> | 56 | <ClCompile Include="resetacls.cpp" /> |
