Skip to content

Build and sign Windows MSIX packages and bundles with Rust

License

Notifications You must be signed in to change notification settings

Choochmeque/msixbundle-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

msixbundle-rs

A Rust library and CLI tool for building and signing Windows MSIX packages and MSIX bundles using the Windows SDK toolchain (MakeAppx and SignTool).

Overview

msixbundle-rs provides a programmatic Rust interface to automate the creation, signing, and validation of multi-architecture MSIX packages and bundles. It's designed for build pipelines that need to package Windows applications for distribution via the Microsoft Store or enterprise deployment.

Features

  • Multi-architecture support: Build separate MSIX packages for x64 and ARM64 architectures
  • Automatic bundle creation: Combine per-architecture packages into a single .msixbundle
  • SDK auto-discovery: Automatically locate Windows SDK tools (MakeAppx.exe, signtool.exe) via registry
  • Code signing: Sign packages and bundles with PFX certificates
  • Timestamping: Support for both RFC3161 and Authenticode timestamp protocols
  • Validation: Verify package structure and signatures using SDK tools
  • Manifest parsing: Extract version and display name from AppxManifest.xml
  • Library and CLI: Use as a Rust library or standalone command-line tool

Components

Library: msixbundle

The core library providing the building blocks for MSIX packaging operations.

Key APIs:

  • locate_sdk_tools() - Find Windows SDK tools on the system
  • read_manifest_info() - Parse AppxManifest.xml for version and identity
  • pack_arch() - Create a per-architecture .msix package
  • build_bundle() - Combine multiple .msix files into a .msixbundle
  • sign_artifact() - Sign packages/bundles with a PFX certificate
  • verify_signature() - Verify digital signatures
  • validate_package() - Check package structure for errors

CLI: msixbundle-cli

Command-line interface for packaging workflows.

Installation

As a CLI tool

cargo install --path msixbundle-cli

As a library

Add to your Cargo.toml:

[dependencies]
msixbundle = "0.1.0"

Usage

CLI Tool

Basic usage - build a bundle from x64 and ARM64 app directories:

msixbundle-cli \
  --out-dir ./output \
  --dir-x64 ./build/x64/AppxContent \
  --dir-arm64 ./build/arm64/AppxContent

Build and sign with a PFX certificate:

msixbundle-cli \
  --out-dir ./output \
  --dir-x64 ./build/x64/AppxContent \
  --dir-arm64 ./build/arm64/AppxContent \
  --pfx ./certificates/signing.pfx \
  --pfx-password "YourPassword" \
  --timestamp-url http://timestamp.digicert.com \
  --timestamp-mode rfc3161

Sign individual architecture packages before bundling:

msixbundle-cli \
  --out-dir ./output \
  --dir-x64 ./build/x64/AppxContent \
  --dir-arm64 ./build/arm64/AppxContent \
  --sign-each \
  --pfx ./signing.pfx \
  --pfx-password "secret"

With validation and verification:

msixbundle-cli \
  --out-dir ./output \
  --dir-x64 ./build/x64/AppxContent \
  --pfx ./signing.pfx \
  --pfx-password "secret" \
  --validate \
  --verify \
  --verbose

CLI Options

Option Description
--out-dir Output directory for generated .msix and .msixbundle files
--dir-x64 Path to x64 AppxContent directory containing AppxManifest.xml
--dir-arm64 Path to ARM64 AppxContent directory
--pfx Path to PFX certificate file for signing
--pfx-password Password for the PFX certificate
--sign-each Sign individual architecture packages (not just the bundle)
--signtool-path Override path to signtool.exe
--sip-dll Path to Appx SIP DLL (e.g., C:\Windows\System32\AppxSip.dll)
--timestamp-url Timestamp server URL (default: http://timestamp.digicert.com)
--timestamp-mode Timestamping protocol: rfc3161 or authenticode (default: rfc3161)
--validate Validate package structure with MakeAppx after building
--verify Verify signatures with SignTool after signing
--verbose Enable verbose logging (sets RUST_LOG=info)

Library API

use msixbundle::*;
use std::path::Path;

fn main() -> anyhow::Result<()> {
    // Locate Windows SDK tools
    let tools = locate_sdk_tools()?;

    // Read manifest information
    let x64_dir = Path::new("./build/x64/AppxContent");
    let manifest = read_manifest_info(x64_dir)?;
    println!("Building {} v{}", manifest.display_name, manifest.version);

    // Pack architectures
    let out_dir = Path::new("./output");
    let x64_msix = pack_arch(&tools, x64_dir, out_dir, &manifest, "x64")?;

    let arm64_dir = Path::new("./build/arm64/AppxContent");
    let arm64_msix = pack_arch(&tools, arm64_dir, out_dir, &manifest, "arm64")?;

    // Build bundle
    let packages = vec![
        ("x64".to_string(), x64_msix),
        ("arm64".to_string(), arm64_msix),
    ];
    let bundle = build_bundle(&tools, out_dir, &packages, &manifest)?;

    // Sign the bundle
    let pfx = Path::new("./signing.pfx");
    sign_artifact(&tools, &SignOptions {
        artifact: &bundle,
        pfx,
        password: Some("password"),
        sip_dll: None,
        timestamp_url: Some("http://timestamp.digicert.com"),
        rfc3161: true,
        signtool_override: None,
    })?;

    // Verify the signature
    verify_signature(&tools, &bundle)?;

    println!("Bundle created: {}", bundle.display());
    Ok(())
}

Requirements

  • Windows OS: This tool requires Windows and the Windows SDK
  • Windows SDK 10: MakeAppx.exe and signtool.exe must be installed
  • Rust: 1.70+ (2021 edition)

The library can automatically discover SDK tools via the Windows registry, or you can provide explicit paths.

How It Works

  1. Manifest Parsing: Reads AppxManifest.xml from each architecture directory to extract version and identity information
  2. Package Creation: Uses MakeAppx.exe to create .msix files for each architecture from the AppxContent directories
  3. Bundle Mapping: Generates a bundlemap.txt file listing all architecture packages
  4. Bundle Creation: Uses MakeAppx.exe to combine packages into a .msixbundle
  5. Signing: Uses signtool.exe to apply digital signatures with optional timestamping
  6. Validation: Optionally verifies package structure and signature validity

Creating a Self-Signed Certificate for Testing

For development and testing, you can create a self-signed certificate. Note: Self-signed certificates are only for local testing. Microsoft Store submissions do not require pre-signing as the Store handles signing automatically.

Important: Certificate Subject Must Match Manifest Publisher

The certificate's Common Name (CN) must exactly match the Publisher attribute in your AppxManifest.xml:

<Identity Name="YourApp" Publisher="CN=YourCompany" Version="1.0.0.0" />

If your manifest has Publisher="CN=YourCompany", your certificate must also have CN=YourCompany.

Using PowerShell (Recommended on Windows)

# Replace "CN=YourCompany" with the Publisher value from your AppxManifest.xml
$cert = New-SelfSignedCertificate -Type Custom -Subject "CN=YourCompany" `
    -KeyUsage DigitalSignature -FriendlyName "MSIX Test Certificate" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")

# Export to PFX file
$password = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\test-certificate.pfx" -Password $password

# Install to Trusted Root (required for local testing/installation)
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Root", "LocalMachine")
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()

Using OpenSSL

# Replace "CN=YourCompany" with the Publisher value from your AppxManifest.xml
# Generate a private key
openssl genrsa -out private.key 2048

# Create a certificate signing request
openssl req -new -key private.key -out request.csr -subj "/CN=YourCompany"

# Generate a self-signed certificate
openssl x509 -req -days 365 -in request.csr -signkey private.key -out certificate.crt

# Export to PFX format
openssl pkcs12 -export -out test-certificate.pfx -inkey private.key -in certificate.crt -password pass:YourPassword

Installing the Certificate for Testing

To install MSIX packages signed with a self-signed certificate on your local machine, the certificate must be in the Trusted Root Certification Authorities store:

Using PowerShell (as Administrator):

Import-PfxCertificate -FilePath ".\test-certificate.pfx" -CertStoreLocation Cert:\LocalMachine\Root -Password (ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText)

Using Certificate Manager (certmgr.msc):

  1. Run certmgr.msc as Administrator
  2. Right-click Trusted Root Certification AuthoritiesAll TasksImport
  3. Select your .pfx file and complete the wizard

Important Notes

  • Microsoft Store: No certificate needed - submit unsigned packages, the Store signs them
  • Enterprise/Sideloading: Use a certificate from a trusted Certificate Authority
  • Local Testing: Self-signed certificates work after installing to Trusted Root
  • Self-signed certificates will cause security warnings on other machines unless installed there too
  • Remove test certificates from Trusted Root after testing for security

Using with msixbundle-cli

Once you have a PFX certificate with matching CN, use it with the tool:

msixbundle-cli \
  --out-dir ./output \
  --dir-x64 ./build/x64/AppxContent \
  --pfx ./test-certificate.pfx \
  --pfx-password "YourPassword"

Project Structure

msixbundle-rs/
├── msixbundle/          # Core library
│   ├── src/
│   │   └── lib.rs       # Main library implementation
│   └── Cargo.toml
├── msixbundle-cli/      # Command-line tool
│   ├── src/
│   │   └── main.rs      # CLI implementation
│   └── Cargo.toml
└── Cargo.toml           # Workspace configuration

Error Handling

The library uses anyhow::Result for error handling and provides custom error types via MsixError:

  • ToolMissing: Windows SDK tool not found
  • MakeAppx: MakeAppx.exe operation failed
  • SignTool: signtool.exe operation failed
  • Manifest: Manifest parsing error

Features

SDK Discovery

Enabled by default. Automatically locates Windows SDK tools via registry.

[dependencies]
msixbundle = { version = "0.1.0", default-features = true }

To disable auto-discovery and provide paths manually:

[dependencies]
msixbundle = { version = "0.1.0", default-features = false }

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

License

MIT License - see the LICENSE file for details.

Resources

See Also

About

Build and sign Windows MSIX packages and bundles with Rust

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors 2

  •  
  •  

Languages