From 5ea1c1b91ec31461fa26d4104b7113fc326cdbcb Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 1 Jun 2022 13:42:18 -0700 Subject: Remote payloads using certificate verification cannot use hash Fixes 6745 --- src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs | 12 +- src/ext/NetFx/wixlib/NetCore3.1.12_x86.wxs | 12 +- src/ext/NetFx/wixlib/NetFx462.wxs | 8 +- src/ext/NetFx/wixlib/NetFx472.wxs | 8 +- src/ext/NetFx/wixlib/NetFx48.wxs | 8 +- .../WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 4 +- .../Bundles/CacheIdGenerator.cs | 45 ++++++ .../Bundles/ProcessExePackageCommand.cs | 11 +- .../Bundles/ProcessMsuPackageCommand.cs | 10 +- .../CommandLine/RemotePayloadSubcommand.cs | 98 +++++++++---- src/wix/WixToolset.Core/Compile/CompilerPayload.cs | 30 ++-- .../ExePackageFixture.cs | 27 ++++ .../MsuPackageFixture.cs | 56 ++++++++ .../PackagePayloadFixture.cs | 3 +- .../RemotePayloadFixture.cs | 159 ++++++++++++++++++--- .../TestData/.Data/fakeba.dll | 1 + .../UseCertificateVerificationWithoutCacheId.wxs | 13 ++ .../BundleUsingCertificateVerification.wxs | 13 ++ ...eUsingCertificateVerificationWithoutCacheId.wxs | 13 ++ .../TestData/MsuPackage/data/fakeba.dll | 1 - .../PackagePayload/SpecifiedCertificate.wxs | 2 +- ...cifiedCertificatePublicKeyWithoutThumbprint.wxs | 2 +- 22 files changed, 440 insertions(+), 96 deletions(-) create mode 100644 src/wix/WixToolset.Core.Burn/Bundles/CacheIdGenerator.cs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/fakeba.dll create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UseCertificateVerificationWithoutCacheId.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerification.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerificationWithoutCacheId.wxs delete mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/data/fakeba.dll (limited to 'src') diff --git a/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs b/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs index b69bb37f..3a1f5910 100644 --- a/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs +++ b/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs @@ -20,8 +20,8 @@ - - + + @@ -35,8 +35,8 @@ - - + + @@ -50,8 +50,8 @@ - - + + diff --git a/src/ext/NetFx/wixlib/NetCore3.1.12_x86.wxs b/src/ext/NetFx/wixlib/NetCore3.1.12_x86.wxs index cf88b32c..e3a70daf 100644 --- a/src/ext/NetFx/wixlib/NetCore3.1.12_x86.wxs +++ b/src/ext/NetFx/wixlib/NetCore3.1.12_x86.wxs @@ -20,8 +20,8 @@ - - + + @@ -35,8 +35,8 @@ - - + + @@ -50,8 +50,8 @@ - - + + diff --git a/src/ext/NetFx/wixlib/NetFx462.wxs b/src/ext/NetFx/wixlib/NetFx462.wxs index cafbee56..904d2be0 100644 --- a/src/ext/NetFx/wixlib/NetFx462.wxs +++ b/src/ext/NetFx/wixlib/NetFx462.wxs @@ -29,8 +29,8 @@ - - + + @@ -51,8 +51,8 @@ - - + + diff --git a/src/ext/NetFx/wixlib/NetFx472.wxs b/src/ext/NetFx/wixlib/NetFx472.wxs index b6d50e75..15cb0de2 100644 --- a/src/ext/NetFx/wixlib/NetFx472.wxs +++ b/src/ext/NetFx/wixlib/NetFx472.wxs @@ -29,8 +29,8 @@ - - + + @@ -51,8 +51,8 @@ - - + + diff --git a/src/ext/NetFx/wixlib/NetFx48.wxs b/src/ext/NetFx/wixlib/NetFx48.wxs index f23f08db..fc2f97f5 100644 --- a/src/ext/NetFx/wixlib/NetFx48.wxs +++ b/src/ext/NetFx/wixlib/NetFx48.wxs @@ -29,8 +29,8 @@ - - + + @@ -51,8 +51,8 @@ - - + + diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 348a4b41..82547487 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs @@ -189,7 +189,7 @@ namespace WixToolset.Core.Burn case WixBundlePackageType.Exe: { - var command = new ProcessExePackageCommand(facade, payloadSymbols); + var command = new ProcessExePackageCommand(this.Messaging, facade, payloadSymbols); command.Execute(); } break; @@ -210,7 +210,7 @@ namespace WixToolset.Core.Burn case WixBundlePackageType.Msu: { - var command = new ProcessMsuPackageCommand(facade, payloadSymbols); + var command = new ProcessMsuPackageCommand(this.Messaging, facade, payloadSymbols); command.Execute(); } break; diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CacheIdGenerator.cs b/src/wix/WixToolset.Core.Burn/Bundles/CacheIdGenerator.cs new file mode 100644 index 00000000..2efa748b --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/Bundles/CacheIdGenerator.cs @@ -0,0 +1,45 @@ +// 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. + +namespace WixToolset.Core.Burn.Bundles +{ + using System; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Services; + + internal static class CacheIdGenerator + { + // These are "reasonable" limits to trim the very long hashes so + // when used in a cache id we do not overflow MAX_PATH. + private const int ReasonableCountOfCharsFromCertificateThumbprint = 20; + private const int ReasonableUpperLimitForCacheId = 64; + + public static string GenerateCacheIdFromPayloadHashAndThumbprint(WixBundlePayloadSymbol payloadSymbol) + { + var takeFromThumbprint = Math.Min(ReasonableCountOfCharsFromCertificateThumbprint, payloadSymbol.CertificateThumbprint.Length); + var takeFromHash = Math.Min(ReasonableUpperLimitForCacheId - takeFromThumbprint, payloadSymbol.Hash.Length); + + return payloadSymbol.Hash.Substring(0, takeFromHash) + payloadSymbol.CertificateThumbprint.Substring(0, takeFromThumbprint); + } + + public static string GenerateCacheIdFromPackagePayloadHash(IMessaging messaging, WixBundlePayloadSymbol packagePayload, string elementName) + { + string cacheId = null; + + // If we are validating the package via certificate, the CacheId must be specified + // in source code. + if (!String.IsNullOrEmpty(packagePayload.CertificatePublicKey) || !String.IsNullOrEmpty(packagePayload.CertificateThumbprint)) + { + var oneOfCertificateAttributeNames = !String.IsNullOrEmpty(packagePayload.CertificatePublicKey) ? "CertificatePublicKey" : "CertificateThumbprint"; + + messaging.Write(ErrorMessages.ExpectedAttribute(packagePayload.SourceLineNumbers, elementName, "CacheId", oneOfCertificateAttributeNames)); + } + else // validating package by hashing, so the CacheId can be defaulted to the hash with a "reasonable" upper limit since the CacheId is in the cached file path. + { + cacheId = packagePayload.Hash.Length > ReasonableUpperLimitForCacheId ? packagePayload.Hash.Substring(0, ReasonableUpperLimitForCacheId) : packagePayload.Hash; + } + + return cacheId; + } + } +} diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs index 8d8ea986..3307db47 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs @@ -4,19 +4,24 @@ namespace WixToolset.Core.Burn.Bundles { using System; using System.Collections.Generic; + using WixToolset.Data; using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Services; /// /// Initializes package state from the Exe contents. /// internal class ProcessExePackageCommand { - public ProcessExePackageCommand(PackageFacade facade, Dictionary payloadSymbols) + public ProcessExePackageCommand(IMessaging messaging, PackageFacade facade, Dictionary payloadSymbols) { - this.AuthoredPayloads = payloadSymbols; + this.Messaging = messaging; this.Facade = facade; + this.AuthoredPayloads = payloadSymbols; } + public IMessaging Messaging { get; } + public Dictionary AuthoredPayloads { get; } public PackageFacade Facade { get; } @@ -30,7 +35,7 @@ namespace WixToolset.Core.Burn.Bundles if (String.IsNullOrEmpty(this.Facade.PackageSymbol.CacheId)) { - this.Facade.PackageSymbol.CacheId = packagePayload.Hash; + this.Facade.PackageSymbol.CacheId = CacheIdGenerator.GenerateCacheIdFromPackagePayloadHash(this.Messaging, packagePayload, "ExePackage"); } this.Facade.PackageSymbol.Version = packagePayload.Version; diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs index 4c61f6d7..b61956a2 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs @@ -6,18 +6,22 @@ namespace WixToolset.Core.Burn.Bundles using System.Collections.Generic; using WixToolset.Data; using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Services; /// /// Processes the Msu packages to add properties and payloads from the Msu packages. /// internal class ProcessMsuPackageCommand { - public ProcessMsuPackageCommand(PackageFacade facade, Dictionary payloadSymbols) + public ProcessMsuPackageCommand(IMessaging messaging, PackageFacade facade, Dictionary payloadSymbols) { - this.AuthoredPayloads = payloadSymbols; + this.Messaging = messaging; this.Facade = facade; + this.AuthoredPayloads = payloadSymbols; } + public IMessaging Messaging { get; } + public Dictionary AuthoredPayloads { private get; set; } public PackageFacade Facade { private get; set; } @@ -28,7 +32,7 @@ namespace WixToolset.Core.Burn.Bundles if (String.IsNullOrEmpty(this.Facade.PackageSymbol.CacheId)) { - this.Facade.PackageSymbol.CacheId = packagePayload.Hash; + this.Facade.PackageSymbol.CacheId = CacheIdGenerator.GenerateCacheIdFromPackagePayloadHash(this.Messaging, packagePayload, "MsuPackage"); } this.Facade.PackageSymbol.PerMachine = true; // MSUs are always per-machine. diff --git a/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs index e812bc8a..83b10c7c 100644 --- a/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs +++ b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs @@ -19,6 +19,9 @@ namespace WixToolset.Core.Burn.CommandLine internal class RemotePayloadSubcommand : BurnSubcommandBase { + private static readonly XName BundlePackageName = "BundlePackage"; + private static readonly XName ExePackageName = "ExePackage"; + private static readonly XName MsuPackageName = "MsuPackage"; private static readonly XName BundlePackagePayloadName = "BundlePackagePayload"; private static readonly XName ExePackagePayloadName = "ExePackagePayload"; private static readonly XName MsuPackagePayloadName = "MsuPackagePayload"; @@ -80,7 +83,7 @@ namespace WixToolset.Core.Burn.CommandLine this.IntermediateFolder = Path.GetTempPath(); } - var elements = this.HarvestRemotePayloads(inputPaths); + var element = this.HarvestPackageElement(inputPaths); if (!this.Messaging.EncounteredError) { @@ -89,14 +92,11 @@ namespace WixToolset.Core.Burn.CommandLine var outputFolder = Path.GetDirectoryName(this.OutputPath); Directory.CreateDirectory(outputFolder); - File.WriteAllLines(this.OutputPath, elements.Select(e => e.ToString())); + File.WriteAllText(this.OutputPath, element.ToString()); } else { - foreach (var element in elements) - { - Console.WriteLine(element); - } + Console.WriteLine(element.ToString()); } } @@ -189,10 +189,51 @@ namespace WixToolset.Core.Burn.CommandLine return result.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } - private IEnumerable HarvestRemotePayloads(IEnumerable paths) + private XElement HarvestPackageElement(IEnumerable paths) + { + var harvestedFiles = this.HarvestRemotePayloads(paths).ToList(); + + XElement element; + + switch (harvestedFiles[0].PackageType) + { + case WixBundlePackageType.Bundle: + element = new XElement(BundlePackageName); + break; + + case WixBundlePackageType.Exe: + element = new XElement(ExePackageName); + break; + + case WixBundlePackageType.Msu: + element = new XElement(MsuPackageName); + break; + + default: + return null; + } + + var packagePayloadFile = harvestedFiles.FirstOrDefault(); + + if (packagePayloadFile != null) + { + if (packagePayloadFile.Element.Attribute("CertificateThumbprint") != null) + { + var cacheId = CacheIdGenerator.GenerateCacheIdFromPayloadHashAndThumbprint(packagePayloadFile.PayloadSymbol); + + element.Add(new XAttribute("CacheId", cacheId)); + } + + element.Add(harvestedFiles.Select(h => h.Element)); + } + + return element; + } + + private IEnumerable HarvestRemotePayloads(IEnumerable paths) { var first = true; - var hashes = this.GetHashes(paths); + var hashes = this.GetCertificateHashes(paths); foreach (var path in paths) { @@ -204,22 +245,22 @@ namespace WixToolset.Core.Burn.CommandLine continue; } + yield return harvestedFile; + if (harvestedFile.PackagePayloads.Any()) { - var packageHashes = this.GetHashes(harvestedFile.PackagePayloads.Select(x => x.SourceFile.Path)); + var packageCertificateHashes = this.GetCertificateHashes(harvestedFile.PackagePayloads.Select(x => x.SourceFile.Path)); foreach (var payloadSymbol in harvestedFile.PackagePayloads) { - var harvestedPackageFile = this.HarvestFile(payloadSymbol.SourceFile.Path, false, packageHashes); - yield return harvestedPackageFile.Element; + var harvestedPackageFile = this.HarvestFile(payloadSymbol.SourceFile.Path, false, packageCertificateHashes); + yield return harvestedPackageFile; } } - - yield return harvestedFile.Element; } } - private Dictionary GetHashes(IEnumerable paths) + private Dictionary GetCertificateHashes(IEnumerable paths) { var hashes = new Dictionary(); @@ -233,7 +274,7 @@ namespace WixToolset.Core.Burn.CommandLine return hashes; } - private HarvestedFile HarvestFile(string path, bool isPackage, Dictionary hashes) + private HarvestedFile HarvestFile(string path, bool isPackage, Dictionary certificateHashes) { XElement element; WixBundlePackageType? packageType = null; @@ -274,7 +315,7 @@ namespace WixToolset.Core.Burn.CommandLine var payloadSymbol = new WixBundlePayloadSymbol(null, new Identifier(AccessModifier.Section, "id")) { SourceFile = new IntermediateFieldPathValue { Path = path }, - Name = Path.GetFileName(path), + Name = this.GetRelativeFileName(path), }; this.PayloadHarvester.HarvestStandardInformation(payloadSymbol); @@ -293,22 +334,18 @@ namespace WixToolset.Core.Burn.CommandLine if (!String.IsNullOrEmpty(this.DownloadUrl)) { - var filename = this.GetRelativeFileName(payloadSymbol.SourceFile.Path); - var formattedUrl = String.Format(this.DownloadUrl, filename); - - if (Uri.TryCreate(formattedUrl, UriKind.Absolute, out var url)) - { - element.Add(new XAttribute("DownloadUrl", url.AbsoluteUri)); - } + element.Add(new XAttribute("DownloadUrl", this.DownloadUrl)); } - if (hashes.TryGetValue(path, out var certificateHashes)) + if (certificateHashes.TryGetValue(path, out var certificateHashForPath)) { - element.Add(new XAttribute("CertificatePublicKey", certificateHashes.PublicKey)); - element.Add(new XAttribute("CertificateThumbprint", certificateHashes.Thumbprint)); - } + payloadSymbol.CertificatePublicKey = certificateHashForPath.PublicKey; + payloadSymbol.CertificateThumbprint = certificateHashForPath.Thumbprint; - if (!String.IsNullOrEmpty(payloadSymbol.Hash)) + element.Add(new XAttribute("CertificatePublicKey", payloadSymbol.CertificatePublicKey)); + element.Add(new XAttribute("CertificateThumbprint", payloadSymbol.CertificateThumbprint)); + } + else if (!String.IsNullOrEmpty(payloadSymbol.Hash)) { element.Add(new XAttribute("Hash", payloadSymbol.Hash)); } @@ -326,6 +363,7 @@ namespace WixToolset.Core.Burn.CommandLine var harvestedFile = new HarvestedFile { Element = element, + PackageType = packageType, PayloadSymbol = payloadSymbol, }; @@ -418,7 +456,11 @@ namespace WixToolset.Core.Burn.CommandLine private class HarvestedFile { public XElement Element { get; set; } + + public WixBundlePackageType? PackageType { get; internal set; } + public WixBundlePayloadSymbol PayloadSymbol { get; set; } + public List PackagePayloads { get; } = new List(); } } diff --git a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs index 2cdc70cf..98ab1579 100644 --- a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs +++ b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs @@ -145,18 +145,11 @@ namespace WixToolset.Core this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile")); } - if (!this.Size.HasValue) - { - this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Size", "SourceFile")); - } - - if (String.IsNullOrEmpty(this.Hash)) - { - this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile")); - } - + // If remote payload is being verified by a certificate. if (!String.IsNullOrEmpty(this.CertificatePublicKey) || !String.IsNullOrEmpty(this.CertificateThumbprint)) { + var oneOfCertificateAttributeNames = !String.IsNullOrEmpty(this.CertificatePublicKey) ? "CertificatePublicKey" : "CertificateThumbprint"; + if (String.IsNullOrEmpty(this.CertificateThumbprint)) { this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificateThumbprint", "CertificatePublicKey")); @@ -165,6 +158,23 @@ namespace WixToolset.Core { this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "CertificatePublicKey", "CertificateThumbprint")); } + + if (!String.IsNullOrEmpty(this.Hash)) + { + this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", oneOfCertificateAttributeNames)); + } + } + else // payload is being verified by hash. + { + if (String.IsNullOrEmpty(this.Hash)) + { + this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile")); + } + + if (!this.Size.HasValue) + { + this.Core.Write(ErrorMessages.ExpectedAttributeWithoutOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Size", "SourceFile")); + } } if (YesNoDefaultType.Yes == this.Compressed) diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs index cebed367..0dba95e1 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs @@ -443,5 +443,32 @@ namespace WixToolsetTest.CoreIntegration Assert.Equal(401, result.ExitCode); } } + + [Fact] + public void CannotBuildBundleWithExePackageUsingCertificateVerificationWithoutCacheId() + { + var dotDatafolder = TestData.Get(@"TestData", ".Data"); + var folder = TestData.Get(@"TestData", "ExePackage"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "UseCertificateVerificationWithoutCacheId.wxs"), + "-bindpath", Path.Combine(folder, "data"), + "-bindpath", dotDatafolder, + "-intermediateFolder", intermediateFolder, + "-o", Path.Combine(baseFolder, "bin", "test.exe") + }); + + Assert.Equal(10, result.ExitCode); + var message = result.Messages.Single(); + Assert.Equal("The ExePackage/@CacheId attribute was not found; it is required when attribute CertificatePublicKey is specified.", message.ToString()); + } + } } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/MsuPackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/MsuPackageFixture.cs index 475afcf0..37499ea9 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/MsuPackageFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/MsuPackageFixture.cs @@ -3,6 +3,7 @@ namespace WixToolsetTest.CoreIntegration { using System.IO; + using System.Linq; using WixBuildTools.TestSupport; using WixToolset.Core.TestPackage; using Xunit; @@ -12,6 +13,7 @@ namespace WixToolsetTest.CoreIntegration [Fact] public void CanBuildBundleWithMsuPackage() { + var dotDatafolder = TestData.Get(@"TestData", ".Data"); var folder = TestData.Get(@"TestData", "MsuPackage"); using (var fs = new DisposableFileSystem()) @@ -24,6 +26,7 @@ namespace WixToolsetTest.CoreIntegration "build", Path.Combine(folder, "Bundle.wxs"), "-bindpath", Path.Combine(folder, "data"), + "-bindpath", dotDatafolder, "-intermediateFolder", intermediateFolder, "-o", Path.Combine(baseFolder, "bin", "test.exe") }); @@ -32,5 +35,58 @@ namespace WixToolsetTest.CoreIntegration Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.exe"))); } } + + [Fact] + public void CanBuildBundleWithMsuPackageUsingCertificateVerification() + { + var dotDatafolder = TestData.Get(@"TestData", ".Data"); + var folder = TestData.Get(@"TestData", "MsuPackage"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundleUsingCertificateVerification.wxs"), + "-bindpath", Path.Combine(folder, "data"), + "-bindpath", dotDatafolder, + "-intermediateFolder", intermediateFolder, + "-o", Path.Combine(baseFolder, "bin", "test.exe") + }); + + result.AssertSuccess(); + Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.exe"))); + } + } + + [Fact] + public void CannotBuildBundleWithMsuPackageUsingCertificateVerificationWithoutCacheId() + { + var dotDatafolder = TestData.Get(@"TestData", ".Data"); + var folder = TestData.Get(@"TestData", "MsuPackage"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundleUsingCertificateVerificationWithoutCacheId.wxs"), + "-bindpath", Path.Combine(folder, "data"), + "-bindpath", dotDatafolder, + "-intermediateFolder", intermediateFolder, + "-o", Path.Combine(baseFolder, "bin", "test.exe") + }); + + Assert.Equal(10, result.ExitCode); + var message = result.Messages.Single(); + Assert.Equal("The MsuPackage/@CacheId attribute was not found; it is required when attribute CertificatePublicKey is specified.", message.ToString()); + } + } } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs index 39caf8fd..f817317d 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs @@ -336,8 +336,9 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { "The ExePackagePayload/@CertificatePublicKey attribute was not found; it is required when attribute CertificateThumbprint is specified.", + "The ExePackagePayload/@Hash attribute cannot be specified when attribute CertificateThumbprint is present." }, result.Messages.Select(m => m.ToString()).ToArray()); - Assert.Equal(10, result.ExitCode); + Assert.Equal(35, result.ExitCode); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs index 9336a635..fc105880 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs @@ -2,6 +2,7 @@ namespace WixToolsetTest.CoreIntegration { + using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -59,9 +60,11 @@ namespace WixToolsetTest.CoreIntegration }; WixAssert.StringEqual( "" + + "" + "" + "" + "" + + "" + "", xml.GetFragmentTestXml(ignoreAttributesByElementName)); // ExternalWithoutDownloadUrl @@ -81,13 +84,15 @@ namespace WixToolsetTest.CoreIntegration xml = File.ReadAllText(externalWithoutDownloadUrlOutFile); WixAssert.StringEqual( "" + + "" + + "" + + "" + + "" + "" + "" + "" + "" + - "" + - "" + - "" + + "" + "", xml.GetFragmentTestXml(ignoreAttributesByElementName)); // External @@ -107,14 +112,16 @@ namespace WixToolsetTest.CoreIntegration xml = File.ReadAllText(externalOutFile); WixAssert.StringEqual( "" + + "" + + "" + + "" + + "" + "" + "" + "" + "" + "" + - "" + - "" + - "" + + "" + "", xml.GetFragmentTestXml(ignoreAttributesByElementName)); // All @@ -134,15 +141,17 @@ namespace WixToolsetTest.CoreIntegration xml = File.ReadAllText(allOutFile); WixAssert.StringEqual( "" + + "" + + "" + + "" + + "" + "" + "" + "" + "" + "" + "" + - "" + - "" + - "" + + "" + "", xml.GetFragmentTestXml(ignoreAttributesByElementName)); } } @@ -173,9 +182,11 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - "", - " ", - "", + "", + " ", + " ", + " ", + "", }, elements); } } @@ -205,7 +216,9 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - @"", + @"", + @" ", + @"", }, elements); } } @@ -234,12 +247,76 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - @"", + @"", + @" ", + @"" }, elements); } } [Fact] + public void CanGetRemoteMsuPayloadWithCertificate() + { + var folder = TestData.Get(@"TestData"); + + using (var fs = new DisposableFileSystem()) + { + var outputFolder = fs.GetFolder(); + var outFile = Path.Combine(outputFolder, "out.xml"); + var remotePayloadSourceFile = Path.Combine(outputFolder, "remotePayload.wxs"); + var intermediateFolder = Path.Combine(outputFolder, "obj"); + var bundleFile = Path.Combine(intermediateFolder, "out.exe"); + + var result = WixRunner.Execute(new[] + { + "burn", "remotepayload", + "-usecertificate", + "-downloadUrl", "http://wixtoolset.org/{0}", + Path.Combine(folder, ".Data", "Windows8.1-KB2937592-x86.msu"), + "-o", outFile + }); + + result.AssertSuccess(); + + var elements = File.ReadAllLines(outFile); + elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); + + WixAssert.CompareLineByLine(new[] + { + @"", + @" ", + @"" + }, elements); + + // Append required attributes to build. + elements[0] = elements[0].Replace(">", " KB='KB2937592' DetectCondition='test'>"); + + var remotePayloadSourceText = "" + + " " + + " " + + String.Join(Environment.NewLine, elements) + + " " + + " " + + ""; + + File.WriteAllText(remotePayloadSourceFile, remotePayloadSourceText); + + result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"), + remotePayloadSourceFile, + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"), + "-bindpath", Path.Combine(folder, ".Data"), + "-intermediateFolder", intermediateFolder, + "-o", bundleFile + }); + + result.AssertSuccess(); + } + } + + [Fact(Skip = "Blocked by https://github.com/wixtoolset/issues/issues/5601 - Support RemotePayload for Payload elements")] public void CanGetRemotePayloadWithCertificate() { var folder = TestData.Get(@"TestData"); @@ -248,11 +325,15 @@ namespace WixToolsetTest.CoreIntegration { var outputFolder = fs.GetFolder(); var outFile = Path.Combine(outputFolder, "out.xml"); + var remotePayloadSourceFile = Path.Combine(outputFolder, "remotePayload.wxs"); + var intermediateFolder = Path.Combine(outputFolder, "obj"); + var bundleFile = Path.Combine(intermediateFolder, "out.exe"); var result = WixRunner.Execute(new[] { "burn", "remotepayload", "-usecertificate", + "-downloadUrl", "http://wixtoolset.org/{0}", Path.Combine(folder, ".Data", "burn.exe"), Path.Combine(folder, ".Data", "signed_cab1.cab"), "-o", outFile @@ -265,9 +346,38 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - @"", - @"", + @"", + @" ", + @" ", + @"", }, elements); + + elements[0] = elements[0].Replace(">", " Permanent='yes' DetectCondition='test'>"); + + var remotePayloadSourceText = "" + + " " + + " " + + " " + + String.Join(Environment.NewLine, elements) + + " " + + " " + + " " + + ""; + + File.WriteAllText(remotePayloadSourceFile, remotePayloadSourceText); + + result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"), + remotePayloadSourceFile, + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"), + "-bindpath", Path.Combine(folder, ".Data"), + "-intermediateFolder", intermediateFolder, + "-o", bundleFile + }); + + result.AssertSuccess(); } } @@ -296,8 +406,10 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - @"", - @"", + @"", + @" ", + @" ", + @"", }, elements); } } @@ -319,6 +431,7 @@ namespace WixToolsetTest.CoreIntegration "-du", "https://www.example.com/files/{0}", Path.Combine(folder, ".Data", "burn.exe"), Path.Combine(folder, "RemotePayload", "recurse", "*"), + "-basepath", Path.Combine(folder, "RemotePayload", "recurse"), "-basepath", folder, "-bp", Path.Combine(folder, ".Data"), "-o", outFile @@ -331,10 +444,12 @@ namespace WixToolsetTest.CoreIntegration WixAssert.CompareLineByLine(new[] { - @"", - @"", - @"", - @"", + @"", + @" ", + @" ", + @" ", + @" ", + @"" }, elements); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/fakeba.dll b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/fakeba.dll new file mode 100644 index 00000000..b3cf17d8 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/fakeba.dll @@ -0,0 +1 @@ +This is a fake BA DLL diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UseCertificateVerificationWithoutCacheId.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UseCertificateVerificationWithoutCacheId.wxs new file mode 100644 index 00000000..49306479 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/UseCertificateVerificationWithoutCacheId.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerification.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerification.wxs new file mode 100644 index 00000000..dcae2cf8 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerification.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerificationWithoutCacheId.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerificationWithoutCacheId.wxs new file mode 100644 index 00000000..f9282e37 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/BundleUsingCertificateVerificationWithoutCacheId.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/data/fakeba.dll b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/data/fakeba.dll deleted file mode 100644 index b3cf17d8..00000000 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/MsuPackage/data/fakeba.dll +++ /dev/null @@ -1 +0,0 @@ -This is a fake BA DLL diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs index b5dec9a2..bee56215 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificate.wxs @@ -3,7 +3,7 @@ - + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs index aa915a31..3694cd72 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedCertificatePublicKeyWithoutThumbprint.wxs @@ -3,7 +3,7 @@ - + -- cgit v1.2.3-55-g6feb