diff --git a/.github/scribe-sign-exe-dll.yml b/.github/scribe-sign-exe-dll.yml new file mode 100644 index 00000000..31def5b0 --- /dev/null +++ b/.github/scribe-sign-exe-dll.yml @@ -0,0 +1,13 @@ +stub: ykman +releaseType: public +jobs: + - name: sign-source + platform: linux + steps: + - id: 1 + action: windows + description: YubiKey Manager + files: + - ykman-builds-windows/ykman/ykman.exe + - ykman-builds-windows/ykman/_internal/pywin32_system32/pythoncom314.dll + - ykman-builds-windows/ykman/_internal/pywin32_system32/pywintypes314.dll \ No newline at end of file diff --git a/.github/scribe-sign-msi.yml b/.github/scribe-sign-msi.yml new file mode 100644 index 00000000..7909ed50 --- /dev/null +++ b/.github/scribe-sign-msi.yml @@ -0,0 +1,11 @@ +stub: ykman +releaseType: public +jobs: + - name: sign-source + platform: linux + steps: + - id: 1 + action: windows + description: YubiKey Manager + files: + - ykman-builds-windows/ykman-installer-windows/ykman.msi \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a547fc01..62f7e679 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -73,3 +73,163 @@ jobs: with: name: ykman-builds-windows path: dist + + sign-exe-dll: + if: startsWith(github.ref, 'refs/tags/') + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Check tag format + run: | + if [[ "${GITHUB_REF}" =~ ^refs/tags/[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then + echo "Tag matches format" + else + echo "Invalid tag format" + exit 1 + fi + + - uses: actions/checkout@v6 + + - name: download artifacts + uses: actions/download-artifact@v5 + with: + path: ykman-builds-windows + + - name: docker login + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ci@yubico.com + password: ${{ secrets.GITHUB_TOKEN }} + + - name: write service account credentials + env: + GAC: ${{ secrets.SCRIBE_SA }} + run: | + echo "${GAC}" > scribe_sa.json + echo "GOOGLE_APPLICATION_CREDENTIALS=/scribe/scribe_sa.json" >> $GITHUB_ENV + + - name: run scribe sign exe and dlls + run: > + docker run + --user $(id -u):$(id -g) + --volume $(pwd):/scribe + --env-file <(env) + ghcr.io/yubico/scribe-ci:v1 + --project-id scribe-prod-987134 + --bucket scribe-u-pub-ykman-fqj0hy + --config /scribe/.github/scribe-sign-exe-dll.yml + submit . + --synchronous + --download-artifacts + + - name: unpack signed exe and dlls + run: | + mkdir -p signed + mv scribe-download/*/sign-source/1.zip signed/ + rm -rf scribe-download + cd signed + unzip -j 1.zip || true + rm 1.zip + cd .. + cp signed/ykman.exe ykman-builds-windows/ykman/ykman.exe + cp signed/pythoncom314.dll ykman-builds-windows/ykman/_internal/pywin32_system32/pythoncom314.dll + cp signed/pywintypes314.dll ykman-builds-windows/ykman/_internal/pywin32_system32/pywintypes314.dll + + - name: upload signed artifacts + uses: actions/upload-artifact@v4 + with: + name: signed-files + path: ykman-builds-windows + + build-msi: + needs: [sign-exe-dll] + runs-on: windows-latest + steps: + - uses: actions/checkout@v6 + + - name: download artifacts + uses: actions/download-artifact@v5 + with: + path: ykman-builds-windows + + - name: Build installer + working-directory: .\ykman-builds-windows\signed-files\ + run: .\scripts\make_msi.ps1 + + - name: Upload installer + uses: actions/upload-artifact@v4 + with: + name: ykman-installer-windows + path: .\ykman-builds-windows\signed-files\ + + sign-msi: + needs: [build-msi] + runs-on: ubuntu-latest + steps: + - name: checkout repo + uses: actions/checkout@v6 + + - name: download artifacts + uses: actions/download-artifact@v5 + with: + path: ykman-builds-windows + + - name: docker login + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ci@yubico.com + password: ${{ secrets.GITHUB_TOKEN }} + + - name: write service account credentials + env: + GAC: ${{ secrets.SCRIBE_SA }} + run: | + echo "${GAC}" > scribe_sa.json + echo "GOOGLE_APPLICATION_CREDENTIALS=/scribe/scribe_sa.json" >> $GITHUB_ENV + + - name: run scribe sign msi + run: > + docker run + --user $(id -u):$(id -g) + --volume $(pwd):/scribe + --env-file <(env) + ghcr.io/yubico/scribe-ci:v1 + --project-id scribe-prod-987134 + --bucket scribe-u-pub-ykman-fqj0hy + --config /scribe/.github/scribe-sign-msi.yml + submit . + --synchronous + --download-artifacts + + - name: unpack signed msi + run: | + mkdir -p signed + mv scribe-download/*/sign-source/1.zip signed/ + rm -rf scribe-download + cd signed + unzip -j 1.zip || true + rm 1.zip + cd .. + cp signed/ykman.msi ykman-builds-windows/ykman-installer-windows/ykman.msi + + - name: upload signed artifacts + uses: actions/upload-artifact@v4 + with: + name: signed-files-and-msi + path: ykman-builds-windows/ykman-installer-windows + + verify-signatures: + needs: [sign-msi] + runs-on: windows-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + name: signed-files-and-msi + path: ykman-builds-windows/ykman-installer-windows + + - name: Check for unsigned DLLs + working-directory: .\ykman-builds-windows\ykman-installer-windows + run: .\scripts\verify_dll.ps1 \ No newline at end of file diff --git a/resources/win/verify_dll.ps1 b/resources/win/verify_dll.ps1 new file mode 100644 index 00000000..d2051684 --- /dev/null +++ b/resources/win/verify_dll.ps1 @@ -0,0 +1,15 @@ +# Set-PSDebug -Trace 1 + +$ErrorActionPreference = "Stop" + +$unsignedDlls = Get-ChildItem -Path "ykman" -Recurse -Filter *.dll | + Where-Object { (Get-AuthenticodeSignature $_.FullName).Status -ne 'Valid' } | + Select-Object -ExpandProperty FullName + +if ($unsignedDlls) { + Write-Host "ERROR: Found unsigned DLL(s):" + $unsignedDlls | ForEach-Object { Write-Host " - $_" } + exit 1 +} else { + Write-Host "SUCCESS: All DLLs are signed." +} \ No newline at end of file