Skip to content
Emmanuel Bourg edited this page Jul 4, 2023 · 12 revisions

Quick overview:

  • The format is zip based, with some restrictions (only STORED and DEFLATED compression methods are supported, multi volume archives are not allowed).

  • The extension is either .appx, .msix, .appxbundle or .msixbundle.

  • The signature is an entry named AppxSignature.p7x, it consists in a PKCS#7 signedData ASN.1 structure prefixed by PKCX.

  • The package contains a [Content_Types].xml file which must be modified with an extra entry for the AppxSignature.p7x file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="dat" ContentType="appv/vfs-file" />
  <Default Extension="png" ContentType="appv/vfs-file" />
  <Default Extension="pri" ContentType="appv/vfs-file" />
  <Default Extension="xml" ContentType="application/vnd.ms-appx.manifest+xml" />
  <Override PartName="/AppxBlockMap.xml" ContentType="application/vnd.ms-appx.blockmap+xml" />
  <Override PartName="/AppxSignature.p7x" ContentType="application/vnd.ms-appx.signature" />
</Types>
  • signtool requires the hash algorithm to match the algorithm defined in the AppxBlockMap.xml entry (as an URI in the HashMethod attribute of the root BlockMap element, see MSIX package signing). The values allowed are:

    But when the signature is verified this requirement isn't checked (at least on Windows 10).

  • The spcSipInfoObjID version is 0x01010000 and the UUID is:

    • 4BDFC50A-07CE-E24D-B76E-23C839A09FD1 for a package (.appx or .msix)
    • B3585F0F-DEAA-9A4B-A434-95742D92ECEB for a bundle (.appxbundle or .msixbundle)
  • Packages and bundles can be differentiated by their content:

    • package have an AppxManifest.xml file
    • bundles have an AppxBundleManifest.xml file
  • The digest in the spcIndirectDataContext structure is a concatenation of several digests. It starts with a header APPX and is followed by 4 or 5 names of 4 bytes in a specific order, followed by a hash (see the DigestName enum). The length of the hash depends on the algorithm used (32 bytes for SHA-256, 48 bytes for SHA-384 and 64 bytes for SHA-512). With SHA-256 the spcIndirectDataContext structure looks like this:

00000000 41 50 50 58 41 58 50 43 FC AB FD 6D E4 B9 CA 86 APPXAXPCü«ýmä¹Ê.
00000010 3B 92 61 66 B1 91 A2 01 F9 5C 39 97 0B 51 6F D6 ;.af±.¢.ù\9..QoÖ
00000020 03 37 7A AF F5 10 9D 36 41 58 43 44 23 3E 5C 59 .7z¯õ..6AXCD#>\Y
00000030 3B 6B E0 F4 D6 11 5A FA 5F 9F 4C 38 D6 57 7C 76 ;kàôÖ.Zú_.L8ÖW|v
00000040 78 5B EB F2 1D 07 43 B3 E6 AF 08 F7 41 58 43 54 x[ëò..C³æ¯.÷AXCT
00000050 C9 86 D8 E1 3E F8 0D 82 BD 75 42 7B 9C 44 42 23 É.Øá>ø..½uB{.DB#
00000060 74 6D 1B B6 EC A8 55 6F 35 08 B8 AE 39 4B C1 19 tm.¶ì¨Uo5.¸®9KÁ.
00000070 41 58 42 4D 2B E5 5D EF 3E 00 08 EE 70 1E AB 04 AXBM+å]ï>..îp.«.
00000080 C2 14 17 10 C6 DE 65 EE E8 26 CD 74 EC 16 13 32 Â...ÆÞeîè&Ítì..2
00000090 75 F2 CF 3A                                     uòÏ:
  • These partial digests are computed as follows (and in this order):

    • AXPC: digest of the file records, i.e. from offset 0 to the last byte before the first central directory file header. The records must be hashed in the order of the central directory (which may not be sorted by offset). When verifying a signed file, the AppxSignature.p7x entry must be skipped.
    • AXCT: digest of the uncompressed content of [ContentTypes].xml
    • AXBM: digest of the uncompressed content of AppxBlockMap.xml
    • AXCD: digest of the central directory. The central directory is hashed completely from the first entry to the end of the file after [Content_Types].xml is modified and before the signature is added to the file, even if it's altered after adding the signature (which means that the signature verification process involves rewriting the central directory as if it didn't contain the signature, this involves changing the number of entries, size and offsets in the end of central directory records).
    • AXCI: digest of the uncompressed content of AppxMetadata/CodeIntegrity.cat, only if the package contains this file.
  • The app manifest publisher name (CN=Contoso) must match the subject name of the signing certificate (CN=Contoso, C=US) (see * https://learn.microsoft.com/en-us/windows/msix/package/signing-known-issues). This means only the publisher of the package can sign it, unlike other file formats.

  • When signing a bundle, signtool also signs the embedded packages. However when the bundle signature is verified, the package signatures aren't checked. So a signed bundle could contain unsigned packages and still be valid.

  • A bundle and its embedded packages must all use the same hash algorithm in their respective AppxBlockMap.xml file.

Resources

Documentation

Sample files

Open source implementations

Clone this wiki locally