From 47fa38f067fd29bd28fc2ad8c0aa1d5665af6844 Mon Sep 17 00:00:00 2001 From: Leon Lynch Date: Sat, 19 Oct 2024 21:14:41 +0200 Subject: [PATCH] Use self-signed openemv.org code signing certificate for MacOS This requires Github Actions to provide these secrets: * OPENEMV_MACOS_CERT_BASE64 * OPENEMV_MACOS_CERT_PWD * KEYCHAIN_PASSWORD A new keychain is created, unlocked, and used to import the code signing certificate. The keychain ACLs are also set to allow the codesign tool to use this keychain without user interaction. The keychain is explicitly cleaned up by the Github Actions workflow. The above functionality is encapsulated in scripts to allow easy reuse but also to avoid the various secrets that are used directly on the command line from appearing in the Github Actions log. --- .github/workflows/macos-build.yaml | 14 +++++++++++- scripts/cleanup_macos_keychain.sh | 8 +++++++ scripts/prepare_macos_keychain.sh | 34 ++++++++++++++++++++++++++++++ viewer/CMakeLists.txt | 34 ++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100755 scripts/cleanup_macos_keychain.sh create mode 100755 scripts/prepare_macos_keychain.sh diff --git a/.github/workflows/macos-build.yaml b/.github/workflows/macos-build.yaml index 22b0274..2139c83 100644 --- a/.github/workflows/macos-build.yaml +++ b/.github/workflows/macos-build.yaml @@ -100,6 +100,13 @@ jobs: - name: Get version from git tag run: echo "GIT_DESCRIBE=$(git describe --always --dirty)" >> $GITHUB_ENV + - name: Prepare keychain + env: + OPENEMV_MACOS_CERT_BASE64: ${{ secrets.OPENEMV_MACOS_CERT_BASE64 }} + OPENEMV_MACOS_CERT_PWD: ${{ secrets.OPENEMV_MACOS_CERT_PWD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: scripts/prepare_macos_keychain.sh + - name: Configure CMake run: | cmake -B build \ @@ -108,7 +115,8 @@ jobs: -DFETCH_ARGP=YES \ -DBUILD_EMV_TOOL=YES \ -DBUILD_EMV_VIEWER=YES \ - -DBUILD_MACOSX_BUNDLE=YES + -DBUILD_MACOSX_BUNDLE=YES \ + -DSIGN_MACOSX_BUNDLE=openemv.org - name: Build run: cmake --build build @@ -119,6 +127,10 @@ jobs: - name: Package run: cmake --build build --target package + - name: Clean up keychain + if: ${{ always() }} + run: scripts/cleanup_macos_keychain.sh + - name: Upload artifact uses: actions/upload-artifact@v4 with: diff --git a/scripts/cleanup_macos_keychain.sh b/scripts/cleanup_macos_keychain.sh new file mode 100755 index 0000000..8ec2c1e --- /dev/null +++ b/scripts/cleanup_macos_keychain.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This script implements the cleanup recommended by: +# https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development + +# Remove temporary keychain +security delete-keychain $RUNNER_TEMP/app-signing.keychain-db + diff --git a/scripts/prepare_macos_keychain.sh b/scripts/prepare_macos_keychain.sh new file mode 100755 index 0000000..02663ce --- /dev/null +++ b/scripts/prepare_macos_keychain.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# This script is inspired by these guides: +# - https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development +# - https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions +# - https://federicoterzi.com/blog/automatic-code-signing-and-notarization-for-macos-apps-using-github-actions/ +# - https://github.com/lando/code-sign-action/ + +# This script assumes that these environment variables are provided: +# - RUNNER_TEMP (temporary directory provided by Github Actions runner) +# - OPENEMV_MACOS_CERT_BASE64 +# - OPENEMV_MACOS_CERT_PWD +# - KEYCHAIN_PASSWORD + +# Temporary paths +OPENEMV_MACOS_CERT_PATH=$RUNNER_TEMP/certificate.p12 +KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + +# Create temporary keychain +security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH +security set-keychain-settings -lut 21600 $KEYCHAIN_PATH +security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + +# Decode and import signing certificate +echo -n "$OPENEMV_MACOS_CERT_BASE64" | base64 --decode > $OPENEMV_MACOS_CERT_PATH +security import $OPENEMV_MACOS_CERT_PATH -P "$OPENEMV_MACOS_CERT_PWD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH +security list-keychains -d user -s $KEYCHAIN_PATH +security find-identity -v -p codesigning + +# Allow codesign application to use signing key +security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + +# Cleanup +rm $OPENEMV_MACOS_CERT_PATH diff --git a/viewer/CMakeLists.txt b/viewer/CMakeLists.txt index e39c8d8..074cc36 100644 --- a/viewer/CMakeLists.txt +++ b/viewer/CMakeLists.txt @@ -252,3 +252,37 @@ install( COMPONENT emv_viewer_bundle DESTINATION . # Install to root of MacOS bundle ) + +# Sign bundle using the specified identity +option(SIGN_MACOSX_BUNDLE "Sign MacOS bundle using the specified identity (use - for ad-hoc signing)") +if(APPLE AND BUILD_MACOSX_BUNDLE AND SIGN_MACOSX_BUNDLE) + find_program(CODESIGN_EXECUTABLE codesign) + if(NOT CODESIGN_EXECUTABLE) + message(FATAL_ERROR "codesign not found") + endif() + + # When using install(CODE) instead of CPACK_PRE_BUILD_SCRIPTS to sign + # the bundle, it must always be the last install() command to ensure + # that all of the bundle files are already present + install(CODE + " + if(TARGET emv-decode) + message(STATUS \"Using identity '${SIGN_MACOSX_BUNDLE}' to sign binary at \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-decode\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-decode\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-decode\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-decode\") + endif() + if(TARGET emv-tool) + message(STATUS \"Using identity '${SIGN_MACOSX_BUNDLE}' to sign binary at \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-tool\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-tool\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-tool\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$/bin/emv-tool\") + endif() + message(STATUS \"Using identity '${SIGN_MACOSX_BUNDLE}' to sign bundle at \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$\") + execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$\") + " + COMPONENT emv_viewer_bundle + ) +endif()