diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml
index 28e8297c..694792dc 100644
--- a/.github/workflows/check-certificates.yml
+++ b/.github/workflows/check-certificates.yml
@@ -26,7 +26,7 @@ jobs:
     if: >
       (github.event_name != 'pull_request' && github.repository == 'arduino/arduino-create-agent') ||
       (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'arduino/arduino-create-agent')
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
 
     strategy:
       fail-fast: false
@@ -37,9 +37,11 @@ jobs:
           - identifier: macOS signing certificate # Text used to identify certificate in notifications.
             certificate-secret: INSTALLER_CERT_MAC_P12  # Name of the secret that contains the certificate.
             password-secret: INSTALLER_CERT_MAC_PASSWORD  # Name of the secret that contains the certificate password.
+            type: pkcs12
           - identifier: Windows signing certificate
-            certificate-secret: INSTALLER_CERT_WINDOWS_PFX
-            password-secret: INSTALLER_CERT_WINDOWS_PASSWORD
+            certificate-secret: INSTALLER_CERT_WINDOWS_CER
+            # The password for the Windows certificate is not needed, because its not a container, but a single certificate.
+            type: x509
 
     steps:
       - name: Set certificate path environment variable
@@ -58,9 +60,10 @@ jobs:
           CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
         run: |
           (
-            openssl pkcs12 \
+            openssl ${{ matrix.certificate.type }} \
               -in "${{ env.CERTIFICATE_PATH }}" \
-              -noout -passin env:CERTIFICATE_PASSWORD
+              -noout -passin env:CERTIFICATE_PASSWORD \
+              -legacy
           ) || (
             echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!"
             exit 1
@@ -83,25 +86,43 @@ jobs:
           CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
         id: get-days-before-expiration
         run: |
-          EXPIRATION_DATE="$(
-            (
-              openssl pkcs12 \
-                -in "${{ env.CERTIFICATE_PATH }}" \
-                -clcerts \
-                -nodes \
-                -passin env:CERTIFICATE_PASSWORD
-            ) | (
-              openssl x509 \
-                -noout \
-                -enddate
-            ) | (
-              grep \
-                --max-count=1 \
-                --only-matching \
-                --perl-regexp \
-                'notAfter=(\K.*)'
-            )
-          )"
+          if [[ ${{ matrix.certificate.type }} == "pkcs12" ]]; then
+            EXPIRATION_DATE="$(
+                (
+                openssl pkcs12 \
+                    -in ${{ env.CERTIFICATE_PATH }} \
+                    -clcerts \
+                    -nodes \
+                    -passin env:CERTIFICATE_PASSWORD \
+                    -legacy
+                ) | (
+                openssl x509 \
+                    -noout \
+                    -enddate
+                ) | (
+                grep \
+                    --max-count=1 \
+                    --only-matching \
+                    --perl-regexp \
+                    'notAfter=(\K.*)'
+                )
+            )"
+          elif [[ ${{ matrix.certificate.type }} == "x509" ]]; then
+            EXPIRATION_DATE="$(
+                (
+                openssl x509 \
+                    -in ${{ env.CERTIFICATE_PATH }} \
+                    -noout \
+                    -enddate
+                ) | (
+                grep \
+                    --max-count=1 \
+                    --only-matching \
+                    --perl-regexp \
+                    'notAfter=(\K.*)'
+                )
+            )"
+          fi
 
           DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))"
 
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 2ae2cf4e..33fe2b7e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -45,7 +45,7 @@ jobs:
       run:
         shell: bash
 
-# by default disable CGO, it's not needed (except on macos)
+    # by default disable CGO, it's not needed (except on macos)
     env:
       CGO_ENABLED: 0
 
@@ -157,7 +157,7 @@ jobs:
   create-macos-bundle:
     needs: build
 
-    # for not they are exaclty the same
+    # for now they are exaclty the same
     strategy:
       matrix:
         arch: [amd64, arm64]
@@ -371,9 +371,6 @@ jobs:
       # vars used by installbuilder
       INSTALLBUILDER_PATH: "/opt/installbuilder-23.11.0/bin/builder"
       INSTALLER_VARS: "project.outputDirectory=$PWD project.version=${GITHUB_REF##*/} workspace=$PWD realname=Arduino_Create_Agent"
-      # installbuilder will read this vars automatically (defined in installer.xml):
-      INSTALLER_CERT_WINDOWS_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
-      INSTALLER_CERT_WINDOWS_PFX: "/tmp/ArduinoCerts2020.pfx"
 
     strategy:
       fail-fast: false # if one os is failing continue nonetheless
@@ -424,11 +421,6 @@ jobs:
       - name: Save InstallBuilder license to file
         run: echo "${{ secrets.INSTALLER_LICENSE }}" > /tmp/license.xml
 
-      - name: Save Win signing certificate to file
-        run: echo "${{ secrets.INSTALLER_CERT_WINDOWS_PFX }}" | base64 --decode > ${{ env.INSTALLER_CERT_WINDOWS_PFX}}
-        if: matrix.os == 'windows-2019'
-
-        # installbuilder reads the env vars with certs paths and use it to sign the installer.
       - name: Launch Bitrock installbuilder
         run: ${{ env.INSTALLBUILDER_PATH }} build installer.xml ${{ matrix.installbuilder-name }} --verbose --license /tmp/license.xml  --setvars ${{ env.INSTALLER_VARS }} architecture=${{ matrix.arch }}
 
@@ -443,6 +435,49 @@ jobs:
           path: ArduinoCreateAgent*
           if-no-files-found: error
 
+  # This job will sign the Windows installer
+  sign-windows:
+    runs-on: [self-hosted, windows-sign-pc]
+    needs: package
+
+    defaults:
+      run:
+        shell: bash
+
+    env:
+      INSTALLER_CERT_WINDOWS_CER: "/tmp/cert.cer"
+      # We are hardcoding the path for signtool because is not present on the windows PATH env var by default.
+      # Keep in mind that this path could change when upgrading to a new runner version
+      SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x86/signtool.exe"
+    
+    strategy:
+      matrix:
+        arch: [amd64, 386]
+    
+    steps:
+      - name: Download artifact
+        uses: actions/download-artifact@v3
+        with:
+          name: ArduinoCreateAgent-windows-${{ matrix.arch }}
+      
+      - name: Save Win signing certificate to file
+        run: echo "${{ secrets.INSTALLER_CERT_WINDOWS_CER }}" | base64 --decode > ${{ env.INSTALLER_CERT_WINDOWS_CER}}
+
+      - name: Sign EXE
+        env:
+          CERT_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
+          CONTAINER_NAME: ${{ secrets.INSTALLER_CERT_WINDOWS_CONTAINER }}
+          # https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
+        run: | 
+          "${{ env.SIGNTOOL_PATH }}" sign -d "Arduino Create Agent" -f ${{ env.INSTALLER_CERT_WINDOWS_CER}} -csp "eToken Base Cryptographic Provider" -k "[{{${{ env.CERT_PASSWORD }}}}]=${{ env.CONTAINER_NAME }}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "ArduinoCreateAgent-${GITHUB_REF##*/}-windows-${{ matrix.arch }}-installer.exe"
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v3
+        with:
+          if-no-files-found: error
+          name: ArduinoCreateAgent-windows-${{ matrix.arch }}-signed
+          path: ArduinoCreateAgent-*-windows-${{ matrix.arch }}-installer.exe
+
   # This job will generate a dmg mac installer, sign/notarize it.
   generate-sign-dmg:
     needs: notarize-macos
@@ -544,7 +579,7 @@ jobs:
   create-release:
     runs-on: ubuntu-20.04
     environment: production
-    needs: [build, package, generate-sign-dmg]
+    needs: [build, generate-sign-dmg, sign-windows]
 
     steps:
       - name: Checkout
@@ -563,7 +598,7 @@ jobs:
           mv -v ArduinoCreateAgent-linux-amd64/* release/
           cat ArduinoCreateAgent-osx-amd64/*.tar | tar -xvf - -i -C release/
           rm -v release/._ArduinoCreateAgent*.dmg
-          mv -v ArduinoCreateAgent-windows*/* release/
+          mv -v ArduinoCreateAgent-windows*-signed/* release/
 
       - name: VirusTotal Scan
         id: virustotal_step