From fed56eed157e21df82f31618fcacd9608336eab5 Mon Sep 17 00:00:00 2001 From: Letao Wang Date: Wed, 24 Sep 2025 09:50:23 -0700 Subject: [PATCH 1/4] md --- specs/packagemanager/PackageManagement.md | 155 ++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index ab8d59bd0c..a091223f85 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -23,6 +23,7 @@ but with additional functionality, improved developer experience and performance - [3.10. PackageVolume Repair](#310-packagevolume-repair) - [3.11. Usability](#311-usability) - [3.12. Is\*Provisioned()](#312-312-isprovisioned) + - [3.13. PackageValidator](#313-packagevalidator) - [4. Examples](#4-examples) - [4.1. AddPackageAsync()](#41-addpackageasync) - [4.2. AddPackageByUriAsync()](#42-addpackagebyuriasync) @@ -73,6 +74,7 @@ Additional functionality includes: * IsPackageRegistrationPending -- Is there an update waiting to register? * PackageSets -- Batch operations * PackageRuntimeManager -- Batch operations for use at runtime via Dynamic Dependencies +* PackageValidator -- Validate a package has expected identity, signature, etc. before adding/staging * Usability -- Quality-of-Life enhancements ## 3.1. API Structure @@ -398,6 +400,24 @@ Is\*Provisioned\*() methods determine if the target is provisioned. These methods require administrative privileges. +## 3.13. PackageValidator + +This API allows callers to verify that packages being processed by PackageDeploymentManager.AddPackageAsync +and PackageDeploymentManager.StagePackageAsync match what are expected from their URI. + +When adding or staging a package from an external source such as HTTP URI or uncontrolled file location, +an attacker can potentially intercept and tamper with the package data being read, causing a malicious +package to be installed instead of the expected one. Verifying the identity and signature of target +packages helps ensure that such tampering has not happened. + +The following PackageValidators are provided and available for use directly: +* PackageFamilyNameValidator: Validates that the package has the expected package family name. +* PackageMinimumVersionValidator: Validates that the package has at least the expected minimum version number. +* PackageCertificateEkuValidator: Validates that the certificate used to sign the package contains the expected Extended Key Usage (EKU) value. + +Custom validators can also be implemented using the IPackageValidator interface, which allows verifying +any part of the package’s footprint data (manifest, block map, and digital signature) in any desired manner. + # 4. Examples ## 4.1. AddPackageAsync() @@ -761,6 +781,100 @@ PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) => }; ``` +## 4.9. PackageValidator + +### 4.9.1. Using built-in PackageValidators + +This example shows how to use built-in PackageValidators to verify package family name, minimum version, and certificate EKU. + +```c++/winrt +auto packageDeploymentManager{ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager::GetDefault() }; +const auto packageUri{ L"https://example.com/package.msix"}; +const winrt::hstring package{ packageUri.c_str() }; + +IVector validators{ winrt::single_threaded_vector() }; +validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageFamilyNameValidator(L"ExpectedFamilyName_abcdefg123")); +validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageMinimumVersionValidator(2, 0, 0, 0)); +validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageCertificateEkuValidator(L"1.3.6.1.4.1.311.2.1.11"); + +winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions addOptions; +addOptions.PackageValidators.Insert(packageUri, validators); + +auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(package, addOptions) }; +auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; +// deploymentOperation will fail with APPX_E_DIGEST_MISMATCH if any packageValidator rejects the package +``` + +### 4.9.2. Using custom PackageValidators + +This example shows how to implement a custom PackageValidator using IPackageValidator interface, and use it to verify a package. + +```idl +// MyCustom.idl +namespace MyCustom +{ + runtimeclass MyPackageValidator : [default] Microsoft.Windows.Management.Deployment.IPackageValidator + { + Boolean IsPackageValid(AppxPackagingObject packagingObject); + } +} +``` + +```c++/winrt +// MyCustom.cpp +// (Assume other standard cppwinrt-generated code related to MyCustom.MyPackageValidator are present. +// This sample only shows the custom hand-written parts.) +namespace winrt::MyCustom::implementation +{ + // Implements a custom package validator that checks that the package does not delcare any capabilities. + struct MyCustomPackageValidator : MyCustomPackageValidatorT + { + MyCustomPackageValidator(); + + bool IsPackageValid(winrt::Microsoft::Windows::Management::Deployment::AppxPackagingObject object) + { + winrt::com_ptr packageReader; + if (FAILED(object.as(packageReader.put()))) + { + // object is not an msix package as expected (i.e. it is a bundle), reject it + return false; + } + + winrt::com_ptr manifestReader; + THROW_IF_FAILED(packageReader->GetManifest(manifestReader.put())); + + winrt::com_ptr manifestReader3; + THROW_IF_FAILED(manifestReader->QueryInterface(manifestReader3.put())); + + winrt::com_ptr capabilitiesEnumerator; + THROW_IF_FAILED(manifestReader3->GetCapabilitiesByCapabilityClass(APPX_CAPABILITY_CLASS_ALL, capabilitiesEnumerator.put())); + + BOOL hasCapabilities{}; + THROW_IF_FAILED(capabilitiesEnumerator->GetHasCurrent(&hasCapabilities)); + return !hasCapabilities; + } + }; +} +``` + +```c++/winrt +// At the call site to PackageDeploymentManager, using the custom package validator +auto packageDeploymentManager{ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager::GetDefault() }; + +const auto packageUri{ L"https://example.com/package.msix"}; +const winrt::hstring package{ packageUri.c_str() }; + +IVector validators{ winrt::single_threaded_vector() }; +validators.Append(winrt::MyCustom::MyPackageValidator()); + +winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options; +options.PackageValidators.Insert(packageUri, validators); + +auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(package, options) }; +auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; +// deploymentOperation will fail with APPX_E_DIGEST_MISMATCH if any packageValidator rejects the package +``` + # 5. Remarks ## 5.1. Platform Support @@ -857,6 +971,41 @@ namespace Microsoft.Windows.Management.Deployment NewerAvailable = 2, }; + [contract(PackageDeploymentContract, 3)] + [default_interface] + runtimeclass AppxPackagingObject{ + // This is an interop class for COM types defined in AppxPackaging.idl. + // The WinRT side has no methods or properties, but the object supports QueryInterface into the COM interfaces + // IAppxPackageReader or IAppxBundleReader, whichever is relevant for the object being read. + } + + [contract(PackageDeploymentContract, 3)] + interface IPackageValidator + { + Boolean IsPackageValid(AppxPackagingObject packagingObject); + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageFamilyNameValidator : [default] IPackageValidator + { + PackageFamilyNameValidator(String expectedPackageFamilyName); + Boolean IsPackageValid(AppxPackagingObject packagingObject); + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageMinimumVersionValidator : [default] IPackageValidator + { + PackageMinimumVersionValidator(UINT major, UINT minor, UINT build, UINT revision); + Boolean IsPackageValid(AppxPackagingObject packagingObject); + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageCertificateEkuValidator : [default] IPackageValidator + { + PackageCertificateEkuValidator(String expectedCertificateEku); + Boolean IsPackageValid(AppxPackagingObject packagingObject); + } + /// The progress status of the deployment request. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress.state [contract(PackageDeploymentContract, 1)] @@ -964,6 +1113,9 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsLimitToExistingPackagesSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) Boolean LimitToExistingPackages; + + Boolean IsPackageValidatorsSupported{ get; }; + IMap> PackageValidators{ get; }; } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -988,6 +1140,9 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsExpectedDigestsSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) IMap ExpectedDigests{ get; }; + + Boolean IsPackageValidatorsSupported{ get; }; + IMap> PackageValidators{ get; }; } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) From 1b356e456e95f038252d6a50d2689ce0e3220651 Mon Sep 17 00:00:00 2001 From: Letao Wang Date: Fri, 26 Sep 2025 09:33:25 -0700 Subject: [PATCH 2/4] updates for PR --- specs/packagemanager/PackageManagement.md | 111 +++++++++++++--------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index a091223f85..089200e0fe 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -402,21 +402,23 @@ These methods require administrative privileges. ## 3.13. PackageValidator -This API allows callers to verify that packages being processed by PackageDeploymentManager.AddPackageAsync -and PackageDeploymentManager.StagePackageAsync match what are expected from their URI. +This API allows callers to verify that packages being processed by Add*, Ensure*, and Stage* APIs of +PackageDeploymentManager match what are expected from their URI. When adding or staging a package from an external source such as HTTP URI or uncontrolled file location, -an attacker can potentially intercept and tamper with the package data being read, causing a malicious -package to be installed instead of the expected one. Verifying the identity and signature of target -packages helps ensure that such tampering has not happened. +a malicious actor might perform a man-in-the-middle attack to intercept and tamper with the package data +being read, causing a malicious package to be installed instead of the expected one. The package might +also be tampered at the source through supply-chain attacks. Verifying the identity and signature of +target packages helps ensure that such attacks have not happened. The following PackageValidators are provided and available for use directly: * PackageFamilyNameValidator: Validates that the package has the expected package family name. * PackageMinimumVersionValidator: Validates that the package has at least the expected minimum version number. * PackageCertificateEkuValidator: Validates that the certificate used to sign the package contains the expected Extended Key Usage (EKU) value. -Custom validators can also be implemented using the IPackageValidator interface, which allows verifying -any part of the package’s footprint data (manifest, block map, and digital signature) in any desired manner. +Custom validators can be implemented using the `IPackageValidator` interface. This can verify any part +of packages' [footprint data](https://learn.microsoft.com/windows/win32/api/appxpackaging/ne-appxpackaging-appx_bundle_footprint_file_type) +(manifest, block map, and digital signature). # 4. Examples @@ -787,22 +789,39 @@ PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) => This example shows how to use built-in PackageValidators to verify package family name, minimum version, and certificate EKU. -```c++/winrt -auto packageDeploymentManager{ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager::GetDefault() }; -const auto packageUri{ L"https://example.com/package.msix"}; -const winrt::hstring package{ packageUri.c_str() }; +```c# +using Microsoft.Windows.Management.Deployment; -IVector validators{ winrt::single_threaded_vector() }; -validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageFamilyNameValidator(L"ExpectedFamilyName_abcdefg123")); -validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageMinimumVersionValidator(2, 0, 0, 0)); -validators.Append(winrt::Microsoft::Windows::Management::Deployment::PackageCertificateEkuValidator(L"1.3.6.1.4.1.311.2.1.11"); +var pdm = PackageDeploymentManager().GetDefault(); +var packageUri = "https://contoso.com/package.msix"; + +var validators = new IList(); +validators.Add(new PackageFamilyNameValidator("ExpectedFamilyName_1234567890abc")); +validators.Add(new PackageMinimumVersionValidator(new Windows.ApplicationModel.PackageVersion(2, 0, 0, 0))); +validators.Add(new PackageCertificateEkuValidator("1.3.6.1.4.1.311.2.1.11")); -winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions addOptions; -addOptions.PackageValidators.Insert(packageUri, validators); +var options = new AddPackageOptions(); +options.Validators.Add(packageUri, validators); -auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(package, addOptions) }; -auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; -// deploymentOperation will fail with APPX_E_DIGEST_MISMATCH if any packageValidator rejects the package +var deploymentResult = await pdm.AddPackageAsync(packageUri, options); +if (deploymentResult.Status == PackageDeploymentStatus.CompletedSuccess) +{ + Console.WriteLine("Success"); +} +else // deploymentResult.Status == PackageDeploymentStatus.CompletedFailure +{ + var error = deploymentResult.Error.HResult; + if (error = 0x80080219 /*APPX_E_DIGEST_MISMATCH*/) + { + Console.WriteLine("The package retrieved from the specified URI isn't expected according to PackageValidators"); + } + else + { + var extendedError = deploymentResult.ExtendedError.HResult; + var message = deploymentResult.MessageText; + Console.WriteLine($"An error occurred while adding the package. Error 0x{error:X08} ExtendedError 0x{extendedError:X08} {message}"); + } +} ``` ### 4.9.2. Using custom PackageValidators @@ -815,7 +834,7 @@ namespace MyCustom { runtimeclass MyPackageValidator : [default] Microsoft.Windows.Management.Deployment.IPackageValidator { - Boolean IsPackageValid(AppxPackagingObject packagingObject); + Boolean IsPackageValid(IInspectable package); } } ``` @@ -831,10 +850,10 @@ namespace winrt::MyCustom::implementation { MyCustomPackageValidator(); - bool IsPackageValid(winrt::Microsoft::Windows::Management::Deployment::AppxPackagingObject object) + bool IsPackageValid(winrt::Microsoft::Foundation::IInspectable package) { winrt::com_ptr packageReader; - if (FAILED(object.as(packageReader.put()))) + if (FAILED(package.as(packageReader.put()))) { // object is not an msix package as expected (i.e. it is a bundle), reject it return false; @@ -861,8 +880,7 @@ namespace winrt::MyCustom::implementation // At the call site to PackageDeploymentManager, using the custom package validator auto packageDeploymentManager{ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager::GetDefault() }; -const auto packageUri{ L"https://example.com/package.msix"}; -const winrt::hstring package{ packageUri.c_str() }; +const winrt::hstring packageUri{ L"https://contoso.com/package.msix" }; IVector validators{ winrt::single_threaded_vector() }; validators.Append(winrt::MyCustom::MyPackageValidator()); @@ -870,9 +888,24 @@ validators.Append(winrt::MyCustom::MyPackageValidator()); winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options; options.PackageValidators.Insert(packageUri, validators); -auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(package, options) }; -auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; -// deploymentOperation will fail with APPX_E_DIGEST_MISMATCH if any packageValidator rejects the package +auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(packageUri, options) }; +auto deploymentResult{ deploymentOperation().get() }; +if (deploymentResult.Status() == winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus::CompletedSuccess) +{ + printf(L"Success!"); +} +else // deploymentResult.Status() == winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentStatus::CompletedFailure) +{ + if (deploymentResult.Error() == APPX_E_DIGEST_MISMATCH) + { + printf("The package retrieved from the specified URI isn't expected according to PackageValidators"); + } + else + { + printf("An error occurred while adding the package. Error 0x%08X ExtendedError 0x%08X %ls", + deploymentResult.Error(), deploymentResult.ExtendedError(), deploymentResult.ErrorMessage().c_str()); + } +} ``` # 5. Remarks @@ -971,39 +1004,31 @@ namespace Microsoft.Windows.Management.Deployment NewerAvailable = 2, }; - [contract(PackageDeploymentContract, 3)] - [default_interface] - runtimeclass AppxPackagingObject{ - // This is an interop class for COM types defined in AppxPackaging.idl. - // The WinRT side has no methods or properties, but the object supports QueryInterface into the COM interfaces - // IAppxPackageReader or IAppxBundleReader, whichever is relevant for the object being read. - } - [contract(PackageDeploymentContract, 3)] interface IPackageValidator { - Boolean IsPackageValid(AppxPackagingObject packagingObject); + // This IInspectable will support QueryInterface into either IAppxPackageReader or + // IAppxBundleReader (these are COM interfaces from AppxPackaging.h). + // One of these interfaces will be available depending on the type of file being validated. + Boolean IsPackageValid(IInspectable package); } [contract(PackageDeploymentContract, 3)] runtimeclass PackageFamilyNameValidator : [default] IPackageValidator { PackageFamilyNameValidator(String expectedPackageFamilyName); - Boolean IsPackageValid(AppxPackagingObject packagingObject); } [contract(PackageDeploymentContract, 3)] runtimeclass PackageMinimumVersionValidator : [default] IPackageValidator { - PackageMinimumVersionValidator(UINT major, UINT minor, UINT build, UINT revision); - Boolean IsPackageValid(AppxPackagingObject packagingObject); + PackageMinimumVersionValidator(Windows.ApplicationModel.PackageVersion minimumVersion); } [contract(PackageDeploymentContract, 3)] runtimeclass PackageCertificateEkuValidator : [default] IPackageValidator { PackageCertificateEkuValidator(String expectedCertificateEku); - Boolean IsPackageValid(AppxPackagingObject packagingObject); } /// The progress status of the deployment request. @@ -1115,7 +1140,7 @@ namespace Microsoft.Windows.Management.Deployment Boolean LimitToExistingPackages; Boolean IsPackageValidatorsSupported{ get; }; - IMap> PackageValidators{ get; }; + IMap > PackageValidators{ get; }; } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1142,7 +1167,7 @@ namespace Microsoft.Windows.Management.Deployment IMap ExpectedDigests{ get; }; Boolean IsPackageValidatorsSupported{ get; }; - IMap> PackageValidators{ get; }; + IMap > PackageValidators{ get; }; } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) From 346c79f37fdb1f60e717046bd6f064d45c2436b3 Mon Sep 17 00:00:00 2001 From: Letao Wang Date: Wed, 1 Oct 2025 17:54:17 -0700 Subject: [PATCH 3/4] view --- specs/packagemanager/PackageManagement.md | 24 ++++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index 089200e0fe..b52b9b69db 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -793,15 +793,12 @@ This example shows how to use built-in PackageValidators to verify package famil using Microsoft.Windows.Management.Deployment; var pdm = PackageDeploymentManager().GetDefault(); -var packageUri = "https://contoso.com/package.msix"; - -var validators = new IList(); -validators.Add(new PackageFamilyNameValidator("ExpectedFamilyName_1234567890abc")); -validators.Add(new PackageMinimumVersionValidator(new Windows.ApplicationModel.PackageVersion(2, 0, 0, 0))); -validators.Add(new PackageCertificateEkuValidator("1.3.6.1.4.1.311.2.1.11")); +var packageUri = new Uri("https://contoso.com/package.msix"); var options = new AddPackageOptions(); -options.Validators.Add(packageUri, validators); +options.AddPackageValidator(packageUri, new PackageFamilyNameValidator("ExpectedFamilyName_1234567890abc")); +options.AddPackageValidator(packageUri, new PackageMinimumVersionValidator(new Windows.ApplicationModel.PackageVersion(2, 0, 0, 0))); +options.AddPackageValidator(packageUri, new PackageCertificateEkuValidator("1.3.6.1.4.1.311.2.1.11")); var deploymentResult = await pdm.AddPackageAsync(packageUri, options); if (deploymentResult.Status == PackageDeploymentStatus.CompletedSuccess) @@ -880,13 +877,10 @@ namespace winrt::MyCustom::implementation // At the call site to PackageDeploymentManager, using the custom package validator auto packageDeploymentManager{ winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentManager::GetDefault() }; -const winrt::hstring packageUri{ L"https://contoso.com/package.msix" }; - -IVector validators{ winrt::single_threaded_vector() }; -validators.Append(winrt::MyCustom::MyPackageValidator()); +const winrt::Windows::Foundation::Uri packageUri{ L"https://contoso.com/package.msix" }; winrt::Microsoft::Windows::Management::Deployment::AddPackageOptions options; -options.PackageValidators.Insert(packageUri, validators); +options.AddPackageValidator(packageUri, winrt::MyCustom::MyPackageValidator()); auto deploymentOperation{ packageDeploymentManager.AddPackageAsync(packageUri, options) }; auto deploymentResult{ deploymentOperation().get() }; @@ -1140,7 +1134,8 @@ namespace Microsoft.Windows.Management.Deployment Boolean LimitToExistingPackages; Boolean IsPackageValidatorsSupported{ get; }; - IMap > PackageValidators{ get; }; + IMapView > PackageValidators{ get; }; + void AddPackageValidator(Windows.Foundation.Uri packageUri, IPackageValidator validator); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1167,7 +1162,8 @@ namespace Microsoft.Windows.Management.Deployment IMap ExpectedDigests{ get; }; Boolean IsPackageValidatorsSupported{ get; }; - IMap > PackageValidators{ get; }; + IMapView > PackageValidators{ get; }; + void AddPackageValidator(Windows.Foundation.Uri packageUri, IPackageValidator validator); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) From 89ff9a61de7a1a93612b5f4bbc2b60f19dcf39e1 Mon Sep 17 00:00:00 2001 From: Letao Wang Date: Wed, 1 Oct 2025 19:50:32 -0700 Subject: [PATCH 4/4] format --- specs/packagemanager/PackageManagement.md | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index b52b9b69db..9e805e2aa2 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -402,22 +402,25 @@ These methods require administrative privileges. ## 3.13. PackageValidator -This API allows callers to verify that packages being processed by Add*, Ensure*, and Stage* APIs of -PackageDeploymentManager match what are expected from their URI. +This API allows callers to verify that packages being processed by Add*, Ensure*, and Stage* APIs +of PackageDeploymentManager match what are expected from their URI. -When adding or staging a package from an external source such as HTTP URI or uncontrolled file location, -a malicious actor might perform a man-in-the-middle attack to intercept and tamper with the package data -being read, causing a malicious package to be installed instead of the expected one. The package might -also be tampered at the source through supply-chain attacks. Verifying the identity and signature of -target packages helps ensure that such attacks have not happened. +When adding or staging a package from an external source such as HTTP URI or uncontrolled file +location, a malicious actor might perform a man-in-the-middle attack to intercept and tamper with +the package data being read, causing a malicious package to be installed instead of the expected +one. The package might also be tampered at the source through supply-chain attacks. Verifying +the identity and signature of target packages helps ensure that such attacks have not happened. The following PackageValidators are provided and available for use directly: * PackageFamilyNameValidator: Validates that the package has the expected package family name. -* PackageMinimumVersionValidator: Validates that the package has at least the expected minimum version number. -* PackageCertificateEkuValidator: Validates that the certificate used to sign the package contains the expected Extended Key Usage (EKU) value. - -Custom validators can be implemented using the `IPackageValidator` interface. This can verify any part -of packages' [footprint data](https://learn.microsoft.com/windows/win32/api/appxpackaging/ne-appxpackaging-appx_bundle_footprint_file_type) +* PackageMinimumVersionValidator: Validates that the package has at least the expected minimum + version number. +* PackageCertificateEkuValidator: Validates that the certificate used to sign the package + contains the expected Extended Key Usage (EKU) value. + +Custom validators can be implemented using the `IPackageValidator` interface. This can verify any +part of packages' +[footprint data](https://learn.microsoft.com/windows/win32/api/appxpackaging/ne-appxpackaging-appx_bundle_footprint_file_type) (manifest, block map, and digital signature). # 4. Examples @@ -823,7 +826,8 @@ else // deploymentResult.Status == PackageDeploymentStatus.CompletedFailure ### 4.9.2. Using custom PackageValidators -This example shows how to implement a custom PackageValidator using IPackageValidator interface, and use it to verify a package. +This example shows how to implement a custom PackageValidator using IPackageValidator interface, +and use it to verify a package. ```idl // MyCustom.idl