All Articles

EV Signing a Tauri Desktop Application

Obstacles Ahead

This post throws you in at the deep end. There’s an excellent blog by Sudara on EV signing in Github actions.

I’ve broken this down into a few sections, as depending on where you’re at you might already have a certificate and just want to get to the Github Action workflow, or you might be stumbling your way through it like I did the first time.

The short of it is, yes you can sign your Tauri application in Github actions using a Cloud HSM provider (Azure) and a certificate authority (GlobalSign).

Provider Choices

Sudara mentions that there are a few Cloud HSM services, but it looks like things have changed a little since the blog was originally written. With AWS offerring CloudHSM to complement the offerings from Azure & GCP.

Some providers offer special ceremonies for a nice added fee. I’ve seen these for AWS and GCP.

Certificate Ceremony, I hope you brought your Key Exchange Hat

I stuck with GlobalSign, it was (fairly) clear that they could work with Azure. I could not say the same about the other providers. The other downside to the other providers is finding a reliable way to make it work with Github Actions. At least now with Microsoft’s ownership of the signing toolchain, Github, and Azure, it seems like they should all work together smoothly.

Ninja Warriors Only - Proving your Identity

I ordered the ‘Extended Validation (EV) Code Signing (HSM)’. There were some issues paying for it, so you might end up having to call them, but everyone I spoke to was very friendly and the process quick.

So what now? This may vary dependent on several factors such as where the company you’re applying for is based, the age of the company, how it is listed, which way the wind is blowing, etc.

You will need:

  • Patience
  • A printer and a scanner 😉
  • A company phone number you can be reached on (and it needs to be verified, so be prepared to get your accountant or solicitor to confirm this in writing, or wait for a letter to be sent to your company address)

For companies under 3 years old you’ll also need:

  • Proof of identity for the applicant
  • A phone number of a colleague who can verify you work for your company (❓❓)

I had a certificate in under a week, but I had my colleagues scrambling to get information, phone numbers redirected, accountants looped in, etc. to ensure we worked our way through it as quickly as possible.

So now I can sign something, right?

Well, not quite. Time to set up Azure and pick up your certificate. When I tried there was this promising shaped button that said something like ‘Add certificates in Key Vault issued by partnered CAs’, and there was even a neat guide. Which of course didn’t work, and instead threw an error. So instead I followed the guide from Sudara but let’s face it, it’ll be different when you try. Good luck.

Once the certificate is set up, continue to follow the guide from Sudara. Assuming you have a Tauri app you can stop before step 6 ‘Package things up’.

Time to sign

Now it’s just time to sign:

name: Build Tauri App
on:
push:
branches:
- main
jobs:
publish-artifacts:
strategy:
fail-fast: false
matrix:
runs_on: [windows-latest]
runs-on: ${{ matrix.runs_on }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install Yarn dependencies
# Shell set to bash, to support MacOS & Windows simultaneously
shell: bash
run: yarn
- name: Build App
# Or whatever your build command is!
run: yarn build
# Shell set to bash, to support MacOS & Windows simultaneously
shell: bash
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Sign Windows App (EV)
if: ${{ matrix.platform == 'windows' }}
run: |
dotnet tool install --global AzureSignTool
# You'll probably want to template in your app version number here somehow
AzureSignTool sign -kvu "${{ secrets.AZURE_KEY_VAULT_URI }}" -kvi "${{ secrets.AZURE_CLIENT_ID }}" -kvt "${{ secrets.AZURE_TENANT_ID }}"-kvs "${{ secrets.AZURE_CLIENT_SECRET }}" -kvc ${{ secrets.AZURE_CERT_NAME }} -tr http://timestamp.digicert.com -v src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi -d "Your Company Name"
- name: Sign Windows Update Bundle
if: ${{ matrix.platform == 'windows' }}
run: |
# These files were generated by the build, but contain a non code signed (EV) version of our app
# So we need to scrap them, and sign our own
rm src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi.zip
rm src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi.zip.sig
# Zip the MSI we signed using AzureSignTool
# Tauri currently zips, but doesn't compress. So we use `-mx=0` which enables copy/store mode
7z a -mx=0 src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi.zip .\src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi
# Generate the `msi.sig` file for the updater!
yarn tauri signer sign src-tauri\target\release\bundle\msi\Your_App_Name_And_Version_0.0.1_x64_en-US.msi.zip --private-key ${{ secrets.TAURI_PRIVATE_KEY }} --password ${{ secrets.TAURI_KEY_PASSWORD }}
view raw tauri_ev.yaml hosted with ❤ by GitHub

That should do it 🙂.

This job runs a matrix despite it only being one OS, but who cares, you’ll probably end up adding another OS soon enough!

I’d recommend injecting version numbers, other secrets, etc. and potentially making this a workflow dispatch job, rather than on push so you can re-use it as a template. All that’s really missing though is uploading your artifacts somewhere at the end!


Cover photo by Phil Shaw on Unsplash

Rope Swing photo by Jakob Owens on Unsplash