mtrojnar / osslsigncode

OpenSSL based Authenticode signing for PE/MSI/Java CAB files
Other
729 stars 124 forks source link

Signing an .appx file corrupts the .appx #367

Closed st-gr closed 3 months ago

st-gr commented 4 months ago

Hi,

First of all, I would like to thank you all for creating this amazing tool that eventually will allow me to build and sign Windows apps running in a Linux/wine docker container.

Irrespective of me building osslsigncode from source or downloading and using the latest release (2.7) downloaded from GitHub the resulting appx gets corrupted.

The appx is created using apache cordova version 11 (yes, I still have to build Windows 8 UWP apps ;-)):

cordova create testapp
cordova platforms add windows
cordova build --debug --arch=x64

(I prevented MSBuild from signing by replacing signtool.exe with a mock executable that returns error code 0).

Here is the command I used to sign the .appx on Windows 10 and Ubuntu 22.04/wine 8.0.2 stable:

osslsigncode sign -in CordovaApp.Windows10_1.0.0.0_x64_debug.appx -out osslsigncode-signed.appx -pkcs12 ..\..\CordovaApp_TemporaryKey.pfx
Hash method is SHA256
Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml
Signing as a package
Succeeded

BTW: The release build 2.7 ran under wine, but the latest source build returned errors and did not sign the file:

Unable to load provider: legacy
Warning: Legacy mode disabled

As a comparison, I signed the .appx using signtool:

PS T:\appxsign-test\platforms\windows\AppPackages\CordovaApp.Windows10_1.0.0.0_x64_debug_Test> ."C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe" sign /fd sha256 /f ..\..\CordovaApp_TemporaryKey.pfx signtool-signed.appx
Done Adding Additional Store
Successfully signed: signtool-signed.appx

When I inspect the corrupted .appx with Z-zip I don't see the packaged files, only one file shows. I then tried to repair the .appx using WinZip which didn't help as this compromised the signature. image

I uploaded the unsigned .appx, the .pfx, and the two signed .appx in this .zip file: appx-files.zip

I haven't checked with a hex editor, yet. There might be a bug in the packaging of the .appx. Microsoft provides an MSIX packaging tool (src/makemsix) that also creates .appx. I thought about looking there for inspiration https://github.com/microsoft/msix-packaging

Your tool is the last puzzle piece for me to be able to build and sign my apps in a Linux/wine container. It took me a while to get MSBuild to behave..

Maybe I am just using your tool with the wrong key format or parameters?

Please advise. st-gr

mtrojnar commented 4 months ago

Irrespective of me building osslsigncode from source or downloading and using the latest release (2.7)

What exactly do you mean by "source" here: the current GitHub master branch or something else?

st-gr commented 4 months ago

Hi mtrojnar,

Sorry for not being specific enough. Yes, I built (VS Buildtools 2022) and tested the current master branch. I didn't know how to create a static build and tested the VS build with the separate libraries on wine which failed. Need to look for static build instructions next time.

Meanwhile I made some observations using the HxD and 010 Hex editors. I created a minimal .appx with 10 KB size. You can download it here: appx-files.zip

1. Signtool keeps the .zip file mostly untouched (files are in the same order after signing compared to osslsigncode):

image

Signtool output vs. osslsigncode: image

2. Osslsigncode seems to add 8 bytes (64 bit) to the zip data stream: image

image

image

3. Osslsigncode is missing the uncompressed and compressed size compared to a WinRAR fixed file: image

4. All but one file offset are wrong. The correct file offset originates from the added AppxSignature.p7x I manually fixed them in the hex editor: image

5. The manually adjusted file appx\rebuilt.osslsigncode-signed-edited.appx passed WinRAR tests, shows that it has a digital signature and loads via installer: image

image

So a manual fix would work and I established that osslsigncode is corrupting the appx zip archive.

The next step will be for me to look at your codebase where the zip (appx) is generated.

If I can't patch your code (because your C++ Kung Fu is better than mine ;-) then a post processing step that applies my manual fixes might do the trick.

Best, st-gr

olszomal commented 4 months ago

I used the App packager MakeAppx.exe to create APPX packages. The APPX file created using Apache Cordova seems to be incompatible with osslsigncode. @panekmaciej Can you take a look?

st-gr commented 4 months ago

Hi olzomal,

MakeAppx.exe is executed by MSBuild when cordova is calling MSBuild to build the .appx. The trouble is that MakeAppx.exe refuses to run under wine (stable 8.0.2) as wine does not implement certain ntdll avl table functions (ReactOS does):

  Task Parameter:Output=C:\windows\temp\hello\platforms\windows\AppPackages\CordovaApp.Windows10_1.0.0.0_x64_debug_Test\CordovaApp.Windows10_1.0.0.0_x64_debug.appx (TaskId:140)
  C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\MakeAppx.exe pack /l /h sha256 /f build\windows\bld\package.map.txt /o /p C:\windows\temp\hello\platforms\windows\AppPackages\CordovaApp.Windows10_1.0.0.0_x
  64_debug_Test\CordovaApp.Windows10_1.0.0.0_x64_debug.appx   (TaskId:140)
wine: Call from 000000017002E8F8 to unimplemented function ntdll.dll.RtlLookupElementGenericTableAvl, aborting
wine: Unimplemented function ntdll.dll.RtlLookupElementGenericTableAvl called at address 000000017002E8F8 (thread 0500), starting debugger...
  Unhandled exception: unimplemented function ntdll.dll.RtlLookupElementGenericTableAvl called in 64-bit code (0x0000017002e8f8). (TaskId:140)

So I make use of the Microsoft MSIX packager instead assuming that the Microsoft tool produces valid appx files. I coded a small stub for MakeAppx.exe that accepts the /f parameter, creates a temporary folder of the files listed in the package.map.txt file, and then runs makemsix.exe using said folder. That is how I got around the above MakeAppx.exe wine issue during the build.

As osslsigntool is targeting to replace signtool to run under Linux (wine) I figure it should support signing any valid appx package I throw its way. Signtool can sign my above makemsix packaged appx, so should osslsigncode.

I followed your suggestion and used MakeAppx.exe on a Windows 10 box at first look the MakeAppx bundled appx does not differ much from the makemsix one: image

The directory size differs dramatically though: image

The 7-zip properties dialog shows “Unsorted_CD” for my makemsix bundled file. It also shows that the makemsix bundled file seems to be compressed more efficiently. image

Maybe that is why the Microsoft engineers chose this Zip64 format for their MSIX packager? ChatGPT:

"Unsorted_CD" in the context of 7-Zip's properties dialog likely refers to an "Unsorted Central Directory." In a ZIP file, the Central Directory (CD) is a section that contains records of all the files stored in the ZIP archive. Each record in the Central Directory provides information about a file, such as its name, size, compression method, and other metadata.

Normally, the records in the Central Directory are sorted in some way, often by file name or by the order in which the files were added to the archive. However, in some cases, the records in the Central Directory might not be sorted. This could happen for various reasons, such as the way the ZIP file was created or modified.

When 7-Zip displays "Unsorted_CD" in the properties dialog, it's indicating that the Central Directory records in the ZIP file are not sorted in the usual manner. This is generally just informational and shouldn't affect your ability to use or extract files from the ZIP archive.

However, there are differences and after I signed the MakeAppx bundled appx with osslsigncode 2.7 it worked! Too bad I can't get MakeAppx.exe to run under Wine.

Now MSIX is the successor of Appx and other application bundle formats. MSIX is less restrictive compared to Appx. Possibly that is the reason why osslsigncode makes assumptions about the internal structure of the appx that are not present in an MSIX bundled appx? Remember: Signtool happily signed my MSIX packaged Appx.

I wonder did anyone here got MakeAppx.exe to run under Wine stable 8.0.2 or are you using a different packager that works with osslsigncode?

Some of the differences in the MSIX packaged Appx throw off osslsigncode, but not signtool. Possibly the unsorted central directory?

Strictly speaking, this is not your problem and I would understand that you won’t support this feature to support signing MSIX files. I might therefore revert to my envisioned post-processing step or ‘fix’ the MSIX packager to create a zip that is like the MakeAppx.exe generated ones.

Best, st-gr

PS: I was wrong about those superfluous 8 byte blocks I identified, yesterday. Zip64 stores size attributes with 8 bytes = uint64 vs. 4 bytes = uint32: image

st-gr commented 3 months ago

Hi,

I discovered that fixing the sort order of the central directory enables osslsigncode to successfully sign makemsix packaged appx files.

I've submitted a pull request to microsoft/msix-packaging to address this by sorting the central directory in the same sequence as the local fileheader streams were added. This workaround resolves the reported issue for me.

Feel free to close this issue. However, it's worth noting that while signtool could sign the appx with unsorted central directory entries, osslsigncode could not without corrupting the archive.

Best, st-gr