2

I am trying to code sign my MAUI Blazor (Windows) app using my EV Code signing cert. I have installed my cert on a YubiKey 5 FIPS device. When I run the below command the app starts to build. Then when it's time to sign the package I am asked for my pin (for the YubiKey). Once the pin is entered I get the below exception.

Command:

"C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\msbuild" /restore /t:Publish /p:TargetFramework=net6.0-windows10.0.19041 /p:configuration=release /p:GenerateAppxPackageOnBuild=true /p:AppxPackageSigningEnabled=true /p:PackageCertificateThumbprint="KeyThumbprint" /p:PackageCertificatePassword="password"

Exception:

C:\Users\user\.nuget\packages\microsoft.windowsappsdk\1.0.0\build\Microsoft.Build.Msix.Packaging.targets(462,5): error
 APPX1204: Failed to sign 'path/to/my.msix'
. SignTool Error: An unexpected internal error has occurred. [path/to/my/project.csproj]
C:\Users\user\.nuget\packages\microsoft.windowsappsdk\1.0.0\build\Microsoft.Build.Msix.Packaging.targets(462,5): error
 APPX1204:  [path/to/my/project.csproj]

Also, if I try the code singing tool I get the below error:

"Error: SignerSign() failed." (-2146435068/0x80100004)

Code Sign.exe Command

signtool.exe sign /fd sha256 /a /sha1 my_thumbprint "path/to/my.msix"

In the past I have gotten a self signed code signint cert to work. This would indicate that the above command is correct.

Travis Pettry
  • 1,220
  • 1
  • 14
  • 35

1 Answers1

0

Visual Studio

You can update the MAUI .csproj file to include the following. This will allow signing in either developer mode or with an EV certificate. I have not specifically used a YubiKey, but it should be the same. Be sure to replace A1B2C3... with your Developer Certificate thumbprint and D4E5F6... with your EV Code Certificate thumbprint.

<PropertyGroup>
    <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <PackageCertificateThumbprint>A1B2C3...</PackageCertificateThumbprint>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
    <PackageCertificateThumbprint>D4E5F6...</PackageCertificateThumbprint>
</PropertyGroup>

<PropertyGroup Condition="$(TargetFramework.Contains('-windows')) and '$(Configuration)' == 'Release'">
    <GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
</PropertyGroup>

PowerShell

Or you can use this PowerShell script to fully automate the publish process and avoid having the EV Code Certificate dialog for the password pop up. This is my preferred method.

There are several replacements here to customize to your project; and if you are using plain text password files please ensure they are saved on some form of secure storage such as a BitLocker VHD.

Some notes:

  • If you have trouble with signing, check this post
  • You will need to replace all of the paths such as C:\MyProject, C:\Logs, or D:\EncryptedStorage with real paths
  • While it is outside of the scope of this answer, it is very easy to extract the version from a .csproj file and replace the 1.0.0.0 with the current version
  • I realize MAUI can target other OSes, but I have not done the work to figure out what needs to change for them
# Update manifest file
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 "D:\EncryptedStorage\MyCertificate.cer"

$file = "C:\MyProject\Platforms\Windows\Package.appxmanifest"
$xml = [Xml] (Get-Content $file)
        
$xml.Package.Identity.Publisher = $certificate.Subject
$xml.Package.Properties.PublisherDisplayName = $certificate.Subject -replace "(CN=)(.*?),.*", '$2'

$xml.Save($file)

# Publish
$dotnet = "C:\Program Files\dotnet\dotnet.exe"

$arguments = New-Object System.Collections.Generic.List[System.String] 

$arguments.Add("publish")
$arguments.Add("C:\MyProject\MyProject.csproj")
$arguments.Add("-c Release")
$arguments.Add("-f net6.0-windows10.0.19041.0")

$publish = Start-Process -NoNewWindow -FilePath $dotnet -PassThru -ArgumentList $arguments.ToArray() -RedirectStandardOutput "C:\Logs\PublishLog.txt"

Wait-Process -InputObject $publish

# Sign
$container = Get-Content "D:\EncryptedStorage\MyCertificateContainer.txt"
$pw = Get-Content "D:\EncryptedStorage\MyCertificatePassword.txt"

$arguments = New-Object System.Collections.Generic.List[System.String] 

$arguments.Add("sign")
$arguments.Add("/tr http://timestamp.sectigo.com")
$arguments.Add("/td SHA256")
$arguments.Add("/f D:\EncryptedStorage\MyCertificate.cer")
$arguments.Add("/fd SHA256")
$arguments.Add("/csp ""eToken Base Cryptographic Provider""")
$arguments.Add("/kc ""[{{${pw}}}]=${container}""")
$arguments.Add("C:\MyProject\bin\Release\net6.0-windows10.0.19041.0\win10-x64\AppPackages\MyProject_1.0.0.0_Test\MyProject_1.0.0.0_x64.msix"))

Copy-Item "D:\EncryptedStorage\MyCertificate.cer" -Destination "C:\MyProject\bin\Release\net6.0-windows10.0.19041.0\win10-x64\AppPackages\MyProject_1.0.0.0_Test\MyProject_1.0.0.0_x64.cer"

$sign = Start-Process -NoNewWindow -FilePath $SignTool -PassThru -ArgumentList $arguments.ToArray() -RedirectStandardOutput "C:\Logs\SignLog.txt"

Wait-Process -InputObject $sign

CLI

Or you can use the dotnet publish command on the command line to publish your application. Again, replace D4E5F6... with your EV Code Certificate thumbprint. And replace CertificatePassword with the password for your certificate (although I would advise using the PowerShell method above to make sure the password is not in your CLI history)

A couple notes:

  • This is currently for Windows, you can change that by updating the -f and removing the /p:GenerateAppxPackageOnBuild=true
  • I have not yet found out how to get the /p:PackageCertificatePassword to bypass popups for EV Code Certificates (such as the SafeNet Authentication Client). Use the PowerShell method for this
dotnet publish C:\MyProject\MyProject.csproj -c Release -f net6.0-windows10.0.19041.0 /p:GenerateAppxPackageOnBuild=true /p:AppxPackageSigningEnabled=true /p:PackageCertificateThumbprint="D4E5F6..." /p:PackageCertificatePassword="CertificatePassword"
The Thirsty Ape
  • 983
  • 3
  • 16
  • 31