dotnet / deployment-tools

This repo contains the code to build the .NET deployment tools and installers for all supported platforms, as well as the sources to .NET deployment tools.
MIT License
169 stars 50 forks source link

ClickOnce EV code sign with USB HSM add support for EDCSA keys #256

Open RhomGit opened 1 year ago

RhomGit commented 1 year ago

Description

I am manually signing application manifest via mage.exe or mageui.exe. I have an EVCS from a CA issued on a USB HSM (Yubikey). signtool.exe has signed the executable correctly using the HSM. mage.exe is reporting "This certificate does not contain a private key" mageui.exe is asking for a Certificate file which I don't have. image

To Reproduce

Try and sign a manifest file using a USB HSM.

.\mage.exe -Sign "C:\my_app.exe.manifest" -csp "Microsoft Smart Card Key Storage Provider" -kc "9b5…" -CertHash "c15…"

Exceptions (if any)

"This certificate does not contain a private key"

Configuration

C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools>

Other information

I have a ticket open with Visual Studio here: https://developercommunity.visualstudio.com/t/ClickOnce-EV-Signing-with-HSM/10278648

I can use signtool to successfully use the HSM for EVCS. This works and I just need mage to do the same. I run the following in PowerShell which prompts for PIN and works perfectly:

cd "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64"
.\signtool.exe sign /fd sha256 /tr http://ts.ssl.com /td sha256 /n "UniqueStringInMyCertificate" "C:\My.exe"

Some others have reverse engineered mage to get this working: https://stackoverflow.com/questions/54752638/mage-exe-manifest-signing-with-certificate-stored-in-aws-cloudhsm

I am happy to help give more feedback/troubleshooting to help resolve this issue. It is affecting many of our clients (today has been awful) as its been sitting triaged for 3 weeks in the other forum and this looks like the appropriate repo for mage. Thanks

Tanya-Solyanik commented 1 year ago

I see multiple potential issues here:

  1. https://github.com/Microsoft/dotnet/issues/986#issuecomment-534970170 - add a code path that attempts to create an Exchange key if a Signature key wasn't found.
  2. Certificate is potentially using SHA384, which is not supported by the build task because SHA2 is hardcoded, even though providers might be available.
Tanya-Solyanik commented 1 year ago

It's possible that the certificate @RhomGit is using has an elliptic curve key, then this is not supported by mage, as it has RSA providers hardcoded in places. In this case your best option is to request a new key.

@RhomGit - to eliminate the easy case, are you using a 64 bit version of mage? Does 64 vs 32 bits make a difference?

RhomGit commented 1 year ago

It was 32 bit. I saw your previous post and downloaded the https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net481-developer-pack-offline-installer and it did indeed place a mage.exe in the x64 subfolder in the Program Files (x86) directory :) C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools\x64\mage.exe

I am heading out to the office now to test (as you can't use the keys over RDP). I will post back soon!

Tanya-Solyanik commented 1 year ago

You would want the latest version as some fixes related to HSM were shipped over time.

To answer your other questions - where to get the .cer file. You should be able to export the public key from your hardware. Perhaps the crypto provider adapter suggests a different file extension for the exported file. For example, Yubico UI suggests .crt or .pem extensions, you can change this extension when exporting. image

To find out if your key is a signature or an exchange key, run the certutil -scinfo command, find your key container in the output and then search for key information

 Key Container = your container
  Provider = your provider
  ProviderType = 1
  Flags = 1
    0x1 (1)
  KeySpec = 2 -- AT_SIGNATURE

The important piece is KeySpec. Mage supports only value 2. If you see:

KeySpec = 1 -- AT_KEYEXCHANGE

Your fastest option is to either request a new certificate or to follow this workaround - Signing using MAGE fails when providing -CertFile -CryptoProvider and -KeyContainer · Issue #986 · microsoft/dotnet (github.com)

RhomGit commented 1 year ago

Alas, I tried x64 and still get this: This certificate does not contain a private key - "xyz" This certificate cannot be used for signing - "xyz"

  Provider = Microsoft Smart Card Key Storage Provider
  ProviderType = 0
  Flags = 1
    0x1 (1)
  KeySpec = 0 -- XCN_AT_NONE
Private key verifies
Microsoft Smart Card Key Storage Provider: KeySpec=0
AES256+RSAES_OAEP(ECC:CNG) test skipped

I have updated to latest YubiKey Manager. Re-downloaded and re-imported the key and still the same results.

I contacted SSL.com to see about a new certificate and finally got a decent response from them. image

I am opting for OV for now since I am in such a predicament with a wide user base. https://www.ssl.com/faqs/which-code-signing-certificate-do-i-need-ev-ov/#smartscreen

Note: I have had issues with eSigner and refuse to use it ever again.

As recommended I have added this a feature request: https://developercommunity.visualstudio.com/t/Add-support-to-ClickOnceMAGE-for-certif/10320755?port=1026&fsid=a18cb832-d063-456d-84c4-51e0dfcabdf2

Thanks

Tanya-Solyanik commented 1 year ago

@RhomGit thank you for the details. So your actual request is for mage and ClickOnce to support EDCSA. I'll modify the bug title accordingly.

RhomGit commented 1 year ago

Hi, @Tanya-Solyanik I am sorry to say that this continues to be a thorn in our business.

OV has unfortunately not been a viable solution as now many of our client organisations are being confronted with SmartScreen (which is embarrassing and confusing to users) and some are having to engage their own I.T departments to workaround the solution every time we publish an update.

I appreciate all of your consideration up to this point however I need to make a serious decision on this so if I could please have some information to go by:

I do value and appreciate your responses thus far.

Thanks, Denis

RhomGit commented 1 year ago

We have decided to engage with alternate CA's to find one that still supports the older RSA method.

RhomGit commented 1 year ago

For anyone trying to use EVCS with ClickOnce I'll keep a list of here of engaged CAs trying to find someone who still supports KeySpec = 2.

The important piece is KeySpec. Mage supports only value 2.

SSL.com

Yubikey was KeySpec = 0 as above.

GlobalSign

response was: We’ve just checked, the KeySpec for our EV CodeSigning certificate is value 1. So the difference is, a KeySpec value of 1, or AT_KEYEXCHANGE, can be used for signing and encryption and value of 2, or AT_SIGNATURE, is only used for signing. May I know if this is acceptable or is there a specific reason that you need the certificate to specifically be KeySpec = 2?

Digicert

Note: many CA seems to use digicert (including Thawte) Great company, very supportive and provided what I required once company was validated. Highly recommended.

tbrentlong commented 9 months ago

Was any resolution reached on this? We have ClickOnce apps as well and need to be able to sign them in a way that shows publisher. We use Azure HSM Key Vault for our cert and it works fine using AzureSignTool to sign the DLLs/EXEs -- but not sure how to handle the ClickOnce manifest signing.

RhomGit commented 9 months ago

I moved to Digicert as my CA who supports KeySpec==2 via physical HSM and published to ClickOnce via Visual Studio directly.

There are instructions here: https://github.com/dotnet/sign for AzureSignTool + ClickOnce support.

plutext commented 9 months ago

The important piece is KeySpec. Mage supports only value 2.

Actually it seems like Command.cs only supports value 1: https://github.com/search?q=keyspec+repo%3Adotnet%2Fdeployment-tools+&type=code

After building this repo, the following works for me:

deployment-tools>.dotnet\dotnet  C:\Users\jh\deployment-tools\artifacts\bin\MageCLI\Debug\net7.0\dotnet-mage.dll -Sign Foo.dll.manifest -csp "eToken Base Cryptographic Provider" -kc "p11#9c60b9999972999d" -CertHash "ffd...2e7"
Foo.dll.manifest successfully signed

This is using a HARICA code signing certificate, which has spec AT_KEYEXCHANGE.

MarkEdward commented 9 months ago

@plutext Did you modify the Command.cs file, or use the current version of the repo as is?

Looking at the history of Command.cs, I don't see what has changed that would make KeySpec == 0 / XCN_AT_NONE certificates work? (I'm using a Yubikey certificate, and so that's the KeySpec type I'm trying to get working in mage)

Connect-and-Exchange commented 9 months ago

Same issue here, ubikey with EV certificate. Following this thread and hopefully mage.exe can be updated to support the EV certificates as well.

jamiehankins commented 6 months ago

Almost a year later, is this support even on Microsoft's roadmap?

Given that signtool can work work these certificates, why can't a dev be assigned to fix dotnet-mage to use the same?

Is ClickOnce no longer a recommended technology from Microsoft?