Microsoft Trusted Code Signing - Steps to set it up

Here is the process which I’m guessing you need to follow for Trusted Signing (FAQ)

It’s from memory, and I had a LOT of mis-steps along the way so please help me to refine these steps

I started from scratch, Create a new email (forwarder)

Create a new Microsoft Account (MSA)

  • make sure to add a phone number
    but do NOT add it as an alternate number

Create an Azure Account using the new MSA

  • https://portal.azure.com (I’ll just call this azure in the future)
    I went in and added some indenty information about the new user
    I have no idea if this matters.

GENERAL TIPS on the Azure Portal:

  • Some UI opens a modal window, there will be a little x in the upper right corner
    that you can use to close (back out of) the window

  • Often buttons are disabled
    I’m told that sometimes it helps to logout and back in again
    it would be nice if they explained why a button is disabled, but no.


Azure Portal

  • Trusted Signing Accounts
    :heavy_plus_sign: Create

    • Project Details:

      • Resource group
        • Create New
          Give it a name
          I appended -RG to the end of my name to indicate it’s a Resource Group
          for this walkthrough I’ll call it LearnTrustedSigning-RG
    • Instance Details:

      • Account name:
        Click on the :information_source: button for restrictions in naming
        I believe this name must be globally unique
        this is the name that will be passed into signtool when you want to sign
        For this walkthrough I’ll call it LearnTrustedSigning-Instance

      • Region
        note: I don’t believe that all regions in the world support trusted signing yet
        I assume that all mentioned in the drop down do support it
        note: the Region you select here, will alter the endpoint passed into signtool

      • Pricing Tier
        see https://azure.microsoft.com/en-us/pricing/details/trusted-signing/
        I used Basic

    • NEXT BUTTON takes you to Tags
      I didn’t add any tags

    • NEXT BUTTON takes you to Review and Create

  • At some point, I was asked to add something to hold secrets
    - I don’t recall where that was
    I was likely lead there by an OVERVIEW pane somewhere
    maybe that was the Resource Group mentioned above

  • Now go into your new Trusted Signing Account - LearnTrustedSigning-Instance

    • Access Control (IAM)
      - :heavy_plus_sign: Add
      • Leave it on Tab[ Job function roles]
        - Search for “Trust”
        • Select “Trusted Signing Identity Verifier”
        • Press NEXT
        • :heavy_plus_sign: Select Members
          Select yourself, the Global Administrator
          (you can select mutliple users here, if you have multiple users
          note: later I will add another “internal” “organizational” user
          which is used for the actual signing
        • PRESS SELECT
        • PRESS Review + Assign
  • Back on Home → LearnTrustedSigning-Instance

    • PRESS Identity validation
      • :heavy_plus_sign: New Identity
        Select Public or Private – I selected Public
        :warning:NOTE they are expecting a website with https://
        if that’s an issue for you, please solve that first

        • NOTE: the business identifier is pre-selected to duns number
          I you don’t have a dun and bradstreet number
          or it has outdated information (our duns had an old address)
          then select a different way to identify your business
          I used a Tax Id and used our EIN

        • from prior experience with Sectigo (Comodo)
          carefully fill out the New Organization validation form
          make sure it’s 100% accurate
          down to each comma and apostrophe

        • PRESS Create

        • Check Email - find the email, and verify the email

        • Wait for them to complete the identity validation
          ours took about 30 minutes !!!
          the subject of the email was: “Trusted Signing identity validation status”

  • Once validated

  • Azure > Trusted Signing Accounts > LearnTrustedSigning-Instance
    - press Certificate profile
    :heavy_plus_sign: Create

    • There are several types
      Public: Public Trust| VBS Enclave|Public Trust Test
      Private: Private Trust| Private Trust CI Policy
      I chose Public Trust

      • Fill in the form
        sorry I can’t open the form right now as the Basic subscription allows only 1 certificate profile

        • You’ll give the certificate a name
          this name will be passed to Signtool
          Let’s call ours LearnTrustedSigning-Cert

          Other fields will include the name of your Organization
          and a street or postal address

      • PRESS Create

  • Click on “Microsoft Azure” upper left to go “Home”

    • Click On Microsoft Entra ID
      (you may need to click on All Services first)
      (later Entra ID is shown as Home > Default Directory)
      • Click on Manage > Users
        • :heavy_plus_sign: New user
          Create new user (to create a new internal user in your organization)
          it will need an email address that does NOT match an existing user that Azure knows about
          I created a new email forwarder for this
          • fill out the rest of form including display name and password
            note the password will need to be replaced shortly
            - I think it might be important to fill in the phone number
            as later you’ll be asked to use the microsoft authentication app on your phone
          • save your login and password to your password database (of course)
          • Press Review+Create
  • Click on Home

  • Click on Trusted Signing Accounts
    - Click on LearnTrustedSigning-Instance (so it shows Home > LearnTrustedSigning-Instance at the top)
    - Access Control (IAM)

    • :heavy_plus_sign: Add (add role assingment)
      Leave it on Tab[ Job function roles]
      • Search for “Trust”
        • Select “Trusted Signing Certificate Profile Signer”
        • Press NEXT
        • :heavy_plus_sign: Select Members
          • Select the new internal user we just created
            FYI: you can select mutliple users here, if you have multiple users
          • PRESS SELECT
          • PRESS Review + Assign

  from admin powershell
  cd to desired folder to install your tools
  PS C:\> Invoke-WebRequest -Uri https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\nuget.exe
         
 .\nuget.exe install Microsoft.Windows.SDK.BuildTools -Version 10.0.22621.3233 -x
 .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -x    

while I used the call above, it's probably a good idea to check which version is preferred

If you want to live dangerously go for the latest version --v
 .\nuget.exe install Microsoft.Trusted.Signing.Client -Version *
     
  • your json file will look like this, examples call this the metadata.json file
       {
            "Endpoint": "https://eus.codesigning.azure.net",
            "CodeSigningAccountName": "LearnTrustedSigning-Instance",
            "CertificateProfileName": "LearnTrustedSigning-Cert",
            "CorrelationId": ""
        }
  • note the endpoint will be different if you used a different region than East US
    to check your region, Azure > LearnTrustedSigning-Instance > Overview > location
    see url in the batch file for see a list of pairs of regions and endpoints

  • To sign a file
    • make sure you have .NET 8 Installed

    • from the same folder as the CallCodeSign.cmd
      C:.…> CallCodeSign TheFilesToSign
      Note: TheFilesToSign can be one file, or a list, can can use wild cards

    • Now, the first time you call SignTool with this configuration

      • a browser tab will open, and you’ll be asked to login
        Select the Internal user we created towards the end of our process
        and fill in the password
        at this point it said since this is the first time logging in
        that I needed to change the password
        do, so, and save your password to your password database (of course)

      • THEN It wanted to have me add the user to the Microsoft Authenication app on my phone
        Open the App on your phone
        Press + at the top
        Select Work or school account
        Scan the QR code on your screen

        • At some point you’ll probably need a thumbprint
          Then they wanted to test the authenticator
          select (or maybe it was type) the number on the screen in the browser into the app
          and press approve
    • If I recall correct, that first code sign failed

    • Try it again, and it worked for me

    • Find someone to celebrate the hard fought victory :partying_face::partying_face::partying_face::partying_face:



see this clarionHub topic for notes on how to use Microsoft Trusted Code Signing with SetupBuilder prior the SetupBuilder 2025 which Friedrich said should be released February 6, 2025


CallCodeSign.cmd —v

:: Created 2025-Jan-22 by Mark Goldberg

@IF .%1.==.. Goto Error

Set SignTool=".\Microsoft.Windows.SDK.BuildTools\bin\10.0.22621.0\x64\signtool.exe"
Set dlib=".\Microsoft.Trusted.Signing.Client\bin\x64\Azure.CodeSigning.Dlib.dll"
Set JsonConfig=".\metadata.json"

%SignTool% sign /v /debug /fd SHA256 /tr "http://timestamp.acs.microsoft.com" /td SHA256 /dlib %dlib% /dmdf %JsonConfig% %*

:: verify is optional
:: %SignTool% verify /v /debug /pa %*

@Goto Done

:: NOTES: ============================================
:: see https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations
::
:: to get the tools you need:
::   from admin powershell
::   cd to desired folder to install your tools
::     PS C:\> Invoke-WebRequest -Uri https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\nuget.exe
::
::     .\nuget.exe install Microsoft.Windows.SDK.BuildTools -Version 10.0.22621.3233 -x
::     .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -x
::
:: while I used the call above, it's probably a good idea to check which version is preferred
:: If you want to live dangerously use -Version * to get the latest version
::  .\nuget.exe install Microsoft.Trusted.Signing.Client -Version *
::
::
:: contents of the file pointed to by %JsonConfig% 
:: {
::     "Endpoint": "https://eus.codesigning.azure.net",
::     "CodeSigningAccountName": "<replace with the name of your Trusted Signing Account>",
::     "CertificateProfileName": "<replace with the name of your Certificate Profile>",
::     "CorrelationId": ""
:: }
::
:: "Endpoint":choose the Endpoint URI value that matches the region you selected when you created the Trusted Signing account that you'll specify next (CSAN)
::    https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations#:~:text=Region%20class%20fields-,Endpoint%20URI%20value,-East%20US
::
:: "CodeSigningAccountName":
::   is the (globally unique) name you gave your Trusted Signing Account
::   portal.azure > trusted signing accounts > use the name from an item in this list (I only have one)
::
:: "CertificateProfileName"
::   portal.azure > trusted signing accounts > click on the name selected above > certificate profile > use the name from an item in this list (I only have one)

:Error
@Echo ===================================================
@Echo ERROR: You must pass in the file(s) to sign
@Echo wild cards are acceptable
@Echo ===================================================

@Goto Done

:Done
7 Likes

Excellent, Mark. What a memory!
Mine is a haze of muddles and the eventual surprise of success.

One thing I’d add… I was a bit unhappy that specifying the “identity” for the code-signing required a street address. But when you create the certificate profile afterwards the default is not to include the detailed address information.

1 Like

This is a really nice write-up Mark! I’ll report back when I have a chance to try it out.

Thanks @MarkGoldberg, your guide helped clear up a few things and I finally got it working. I initially could not get code signing to work when trying to use the personal Microsoft Account username/password during the browser flow, but your instruction regarding “Users” helped me find a solution, one that doesn’t actually require a second/dummy user. Read on for my slight tweaks to your very thorough guide!

A few things worth noting, during the quoted step below…

…you can alternatively click the “Organization” dropdown and opt for “Individual” here if you want an individual identity, associated only with yourself, e.g. your name, and a house address. Don’t worry, even with a “Public” identity/certificate, when setting up a “Certificate profile” later, you can conceal that address. You will then follow through identity verification like submitting a picture of your ID and a recent billing statement with your name and address on it.

Now, here’s the other slight tweak compared with your approach, which allowed me to avoid creating a second alt/dummy user. This has to do with a “mirror account” that already exists and is tied to your personal Microsoft account, and can be logged into using the “user principal name” found in Azure (which differs from your actual email/password login).

Here is the relevant section of your guide…

and here is how I would modify it…

  • Click On Microsoft Entra ID
    (you may need to click on All Services first)
    (later Entra ID is shown as Home > Default Directory)
    • Click on Manage > Users
      • Click on yourself, the only user
      • Click the “copy to clipboard” icon on the User principal name entry
      • Open an Incognito window to https://login.microsoftonline.com/ and sign in with that username, e.g. [email protected]. When prompted with a password, click “forgot” and proceed to reset your password via email to your primary email address (this is and will be a different, unique password from your Microsoft account password!)
      • Configure 2FA, again this will be a unique 2FA method independent of the one for your personal Microsoft account
      • Complete the login flow, save the username/password for logging in to sign your software later!

Then, when assigning roles to myself, the only user (as opposed to your two-user flow), I gave myself BOTH of the “Trusted Signing Identity Verifier” and “Trusted Signing Certificate Profile Signer” roles.

I would also specify some ExcludeCredentials in the JSON, modifying yours to be…

{
  "Endpoint": "https://eus.codesigning.azure.net",
  "CodeSigningAccountName": "LearnTrustedSigning-Instance",
  "CertificateProfileName": "LearnTrustedSigning-Cert",
  "CorrelationId": "UNIQUE-MACHINE-NAME-IF-DESIRED-OR-EMPTY-STRING"
  "ExcludeCredentials": [
    "AzureCliCredential",
    "AzureDeveloperCliCredential",
    "AzurePowerShellCredential",
    "EnvironmentCredential",
    "ManagedIdentityCredential",
    "SharedTokenCacheCredential",
    "VisualStudioCodeCredential",
    "VisualStudioCredential",
    "WorkloadIdentityCredential"
  ]
}

Though your endpoint may vary, e.g. wus or something. Also, it’s notable that wus3 supports Azure Trusted Signing despite one of their official help articles suggesting maybe it doesn’t.

Most of those ExcludeCredentials entries speeds up the signing flow, and we omit InteractiveBrowserCredential so that we can force that one. Notice that SharedTokenCacheCredential seems to sort of magically cache your signing key, not sure for how long and how it gets invalidated, but it’s probably best to exclude that one too! That way you’re always forced through the browser flow when signing (which should be an infrequent but very security-sensitive action).

Anyways this took me all day to sort out, so I’m really glad I found your guide. It’s awesome that code signing is now available to any individual for $10/mo. but clearly there’s still a ton of very devops/IT flaming hoops to jump through, and easy to get burned.

2 Likes

A follow up to my post above, I’ve found that Jsign (v7 and up) has a nicer Azure Trusted Signing implementation than Signtool, though it does require using Azure CLI to grab a (short-lived) access token, so embedding it as follows avoids hard-coding that token…

jsign \
    --storetype 'TRUSTEDSIGNING' \
    --keystore '{{region}}.codesigning.azure.net' \
    --alias '{{account}}/{{profile}}' \
    --storepass (az account get-access-token \
      --resource 'https://codesigning.azure.net' \
      --query 'accessToken' \
    ) \
    '{{my-binary}}.exe'

It has sensible defaults so you don’t have to specify as many flags as with signtool, plus it works on Windows/Linux/MacOS.

1 Like

I’m going through this myself, and it’s been 7 days waiting for the identity validation (after providing additional details). How long have others had to wait?

In the meantime, we’re trying to use a self-signed cert and we’re running into a rather interesting problem on our build server. FYI, it’s an AWS VM running Windows Server 2016. It was working fine signing with SetupBuilder, until the prior cert expired.

When we tried replacing the old cert with the self-signed cert (which has the same password), SetupBuilder reports an error:

Compiler error GEN1053: Code signing process failed. Error Code: 2

Attempting to debug this, we tried to run signtool from the command line, and we get the error:

SignTool Error: The specified PFX password is not correct.

However, I created this cert myself, and it absolutely has the same password as before. Additionally, we are able to use this same self-signed cert successfully on our local machines.

Just in case, we tried to import the cert with the Windows wizard, and it also complained about an incorrect password. :thinking: Again, this import works fine on our local machines.

We have disabled anti-virus for the applicable folders, so it’s not that.

Is anyone aware of configuration issues that might cause this errant behavior? Perhaps Group Policy settings that might be block it? We spotted one message from someone who said that they solved it by upgrading from Windows Server 2016 to 2019, but I suspect that was more likely do to some other difference between the machines.

Mike,
My verification took under a half hour. Not sure why it’s taking so long for you.

To test the certificate password try:
openssl pkcs12 -info -in “YourCertificate.pfx”

This will prompt you for the password and display info on the cert.

Edit: My company is a Microsoft Partner. That might have helped the verification process.

My verification also took less than an hour, Mike. Supplied my DUNS number and that was apparently all it needed.

It may have be related to the encryption level. I had exported it as AES256-SHA256. We tried it as the lesser TripleDES-SHA1, and at least SignTool works from the command line. Curiously, SetupBuilder will stumbles, but at least we’re making progress. :man_shrugging:

You know about this pragma in Setup Builder, right?
image

The self-signed certificate part of this thread should probably be a separate topic… :slight_smile:

I have just uploaded SetupBuilder 2025 (BETA), which comes with a brand new code-signing mechanism to handle .pfx, Microsoft Trusted Signing, eToken and Cloud certificates.

Still working on the new code-signing instructions. We’ll send new login details to more SetupBuilder users tomorrow.

Friedrich

Looks like this now in SB2025…

More information soon ™.

Friedrich

1 Like

I like the optional DLIB location, Friedrich :slight_smile:

(And the rest, of course!)

1 Like

Quick info: I tested self-signed AES256-SHA256 and TripleDES-SHA1 certificates with SetupBuilder 2025 and it’s working fine (SHA-1, SHA-2 and dual SHA-1/SHA-2). I have completely rewritten the compiler module in SB 2025 that handles code-signing.

But of course, Microsoft Trusted Signing is the new king in town. I LOVE IT!!! Way faster than my EV eToken (with no SafeNet support) and even faster than my EV Cloud certificate.

Friedrich

I’ll add two more comments.
I had to install the .Net 8 runtime on a couple of my systems to get the signing to work.
Additionally, on a AWS EC2 server (Windows Server 2019 Data Center) I had to exclude ManagedIdentityCredential in my json file. Otherwise, the signing process was generating errors:
ManagedIdentityCredential authentication failed “404”

Hi Rick,

yes, .NET 8 Runtime is required. Our “SignInstall for SetupBuilder 2025” runtime checks for .NET 8 and (if available) downloads and installs the code-signing dependency files.

In the next SB 2025 BETA it will even provide an option to download and install .NET 8 Runtime if not available.

Thanks for the ManagedIdentityCredential information. Very interesting!!!

Microsoft Trusted Signing works absolutely perfect and is a game-changer in code signing (IMO).

Friedrich

I’ve been waiting for the identity validation for weeks now, without changing from “In Progress”. I’ve actually started multiple attempts, all of which are stuck in this phase. There doesn’t seem to be any way to contact them to ask what’s going on. Does anyone have any experience that might help me?

My entire identify validation process took roughly 30 minutes
My guess is you missed the email verification
which by now is no longer valid

Have you checked your mail and verified it?
If you click on the Identity Validation it should show what it’s waiting for in the drawn out

To add, just set up SetupBuilder 2025 and ran the Microsoft Trust Singing test, it succeeded!

1 Like

Mine was still valid after a week - so maybe his is too