Skip to content

Commit

Permalink
Use self-signed openemv.org code signing certificate for MacOS
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
leonlynch committed Oct 19, 2024
1 parent 4245d36 commit 47fa38f
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
14 changes: 13 additions & 1 deletion .github/workflows/macos-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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
Expand All @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions scripts/cleanup_macos_keychain.sh
Original file line number Diff line number Diff line change
@@ -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

34 changes: 34 additions & 0 deletions scripts/prepare_macos_keychain.sh
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions viewer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-decode\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-decode\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-decode\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-decode\")
endif()
if(TARGET emv-tool)
message(STATUS \"Using identity '${SIGN_MACOSX_BUNDLE}' to sign binary at \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-tool\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-tool\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-tool\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_CONTENT_DIR:emv-viewer>/bin/emv-tool\")
endif()
message(STATUS \"Using identity '${SIGN_MACOSX_BUNDLE}' to sign bundle at \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_DIR_NAME:emv-viewer>\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --sign \"${SIGN_MACOSX_BUNDLE}\" --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_DIR_NAME:emv-viewer>\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --display --verbose --verbose=4 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_DIR_NAME:emv-viewer>\")
execute_process(COMMAND ${CODESIGN_EXECUTABLE} --verify --verbose --deep \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\$<TARGET_BUNDLE_DIR_NAME:emv-viewer>\")
"
COMPONENT emv_viewer_bundle
)
endif()

0 comments on commit 47fa38f

Please sign in to comment.