diff --git a/contrib/guix/guix-codesign b/contrib/guix/guix-codesign index 4694209e00d..dedee135b4a 100755 --- a/contrib/guix/guix-codesign +++ b/contrib/guix/guix-codesign @@ -137,7 +137,7 @@ fi ################ -# Unsigned tarballs SHOULD exist +# Codesigning tarballs SHOULD exist ################ # Usage: outdir_for_host HOST SUFFIX @@ -149,13 +149,13 @@ outdir_for_host() { } -unsigned_tarball_for_host() { +codesigning_tarball_for_host() { case "$1" in *mingw*) - echo "$(outdir_for_host "$1")/${DISTNAME}-win64-unsigned.tar.gz" + echo "$(outdir_for_host "$1")/${DISTNAME}-win64-codesigning.tar.gz" ;; *darwin*) - echo "$(outdir_for_host "$1")/${DISTNAME}-${1}-unsigned.tar.gz" + echo "$(outdir_for_host "$1")/${DISTNAME}-${1}-codesigning.tar.gz" ;; *) exit 1 @@ -164,22 +164,22 @@ unsigned_tarball_for_host() { } # Accumulate a list of build directories that already exist... -hosts_unsigned_tarball_missing="" +hosts_codesigning_tarball_missing="" for host in $HOSTS; do - if [ ! -e "$(unsigned_tarball_for_host "$host")" ]; then - hosts_unsigned_tarball_missing+=" ${host}" + if [ ! -e "$(codesigning_tarball_for_host "$host")" ]; then + hosts_codesigning_tarball_missing+=" ${host}" fi done -if [ -n "$hosts_unsigned_tarball_missing" ]; then +if [ -n "$hosts_codesigning_tarball_missing" ]; then # ...so that we can print them out nicely in an error message cat << EOF -ERR: Unsigned tarballs do not exist +ERR: Codesigning tarballs do not exist ... EOF -for host in $hosts_unsigned_tarball_missing; do - echo " ${host} '$(unsigned_tarball_for_host "$host")'" +for host in $hosts_codesigning_tarball_missing; do + echo " ${host} '$(codesigning_tarball_for_host "$host")'" done exit 1 fi @@ -371,7 +371,7 @@ EOF OUTDIR="$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)" \ DIST_ARCHIVE_BASE=/outdir-base/dist-archive \ DETACHED_SIGS_REPO=/detached-sigs \ - UNSIGNED_TARBALL="$(OUTDIR_BASE=/outdir-base && unsigned_tarball_for_host "$HOST")" \ + CODESIGNING_TARBALL="$(OUTDIR_BASE=/outdir-base && codesigning_tarball_for_host "$HOST")" \ bash -c "cd /bitcoin && bash contrib/guix/libexec/codesign.sh" ) diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index ddb8297d9e6..389706a8cf4 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -281,24 +281,6 @@ mkdir -p "$DISTSRC" ;; esac - case "$HOST" in - *darwin*) - cmake --build build --target deploy ${V:+--verbose} - mv build/dist/Bitcoin-Core.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip" - mkdir -p "unsigned-app-${HOST}" - cp --target-directory="unsigned-app-${HOST}" \ - contrib/macdeploy/detached-sig-create.sh - mv --target-directory="unsigned-app-${HOST}" build/dist - ( - cd "unsigned-app-${HOST}" - find . -print0 \ - | sort --zero-terminated \ - | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ - | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \ - || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 ) - ) - ;; - esac ( cd installed @@ -327,7 +309,7 @@ mkdir -p "$DISTSRC" cp -r "${DISTSRC}/share/rpcauth" "${DISTNAME}/share/" - # Finally, deterministically produce {non-,}debug binary tarballs ready + # Deterministically produce {non-,}debug binary tarballs ready # for release case "$HOST" in *mingw*) @@ -335,8 +317,8 @@ mkdir -p "$DISTSRC" | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" find "${DISTNAME}" -not -name "*.dbg" \ | sort \ - | zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" \ - || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" && exit 1 ) + | zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-unsigned.zip" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-unsigned.zip" && exit 1 ) find "${DISTNAME}" -name "*.dbg" -print0 \ | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" find "${DISTNAME}" -name "*.dbg" \ @@ -360,12 +342,13 @@ mkdir -p "$DISTSRC" find "${DISTNAME}" -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ - | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \ - || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 ) + | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 ) ;; esac ) # $DISTSRC/installed + # Finally make tarballs for codesigning case "$HOST" in *mingw*) cp -rf --target-directory=. contrib/windeploy @@ -373,11 +356,31 @@ mkdir -p "$DISTSRC" cd ./windeploy mkdir -p unsigned cp --target-directory=unsigned/ "${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe" + cp -r --target-directory=unsigned/ "${INSTALLPATH}" + find unsigned/ -name "*.dbg" -print0 \ + | xargs -0r rm find . -print0 \ | sort --zero-terminated \ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ - | gzip -9n > "${OUTDIR}/${DISTNAME}-win64-unsigned.tar.gz" \ - || ( rm -f "${OUTDIR}/${DISTNAME}-win64-unsigned.tar.gz" && exit 1 ) + | gzip -9n > "${OUTDIR}/${DISTNAME}-win64-codesigning.tar.gz" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-win64-codesigning.tar.gz" && exit 1 ) + ) + ;; + *darwin*) + cmake --build build --target deploy ${V:+--verbose} + mv build/dist/Bitcoin-Core.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip" + mkdir -p "unsigned-app-${HOST}" + cp --target-directory="unsigned-app-${HOST}" \ + contrib/macdeploy/detached-sig-create.sh + mv --target-directory="unsigned-app-${HOST}" build/dist + cp -r --target-directory="unsigned-app-${HOST}" "${INSTALLPATH}" + ( + cd "unsigned-app-${HOST}" + find . -print0 \ + | sort --zero-terminated \ + | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ + | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-codesigning.tar.gz" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-codesigning.tar.gz" && exit 1 ) ) ;; esac diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh index b56d2a23094..3a729371114 100755 --- a/contrib/guix/libexec/codesign.sh +++ b/contrib/guix/libexec/codesign.sh @@ -4,6 +4,9 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C set -e -o pipefail + +# Environment variables for determinism +export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name" export TZ=UTC # Although Guix _does_ set umask when building its own packages (in our case, @@ -27,7 +30,7 @@ fi # Check that required environment variables are set cat << EOF Required environment variables as seen inside the container: - UNSIGNED_TARBALL: ${UNSIGNED_TARBALL:?not set} + CODESIGNING_TARBALL: ${CODESIGNING_TARBALL:?not set} DETACHED_SIGS_REPO: ${DETACHED_SIGS_REPO:?not set} DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set} DISTNAME: ${DISTNAME:?not set} @@ -63,27 +66,54 @@ mkdir -p "$DISTSRC" ( cd "$DISTSRC" - tar -xf "$UNSIGNED_TARBALL" + tar -xf "$CODESIGNING_TARBALL" mkdir -p codesignatures tar -C codesignatures -xf "$CODESIGNATURE_GIT_ARCHIVE" case "$HOST" in *mingw*) - find "$PWD" -name "*-unsigned.exe" | while read -r infile; do - infile_base="$(basename "$infile")" - - # Codesigned *-unsigned.exe and output to OUTDIR + # Apply detached codesignatures + WORKDIR=".tmp" + mkdir -p ${WORKDIR} + cp -r --target-directory="${WORKDIR}" "unsigned/${DISTNAME}" + find "${WORKDIR}/${DISTNAME}" -name "*.exe" -type f -exec rm {} \; + find unsigned/ -name "*.exe" -type f | while read -r bin + do + bin_base="$(realpath --relative-to=unsigned/ "${bin}")" + mkdir -p "${WORKDIR}/$(dirname "${bin_base}")" osslsigncode attach-signature \ - -in "$infile" \ - -out "${OUTDIR}/${infile_base/-unsigned}" \ + -in "${bin}" \ + -out "${WORKDIR}/${bin_base/-unsigned}" \ -CAfile "$GUIX_ENVIRONMENT/etc/ssl/certs/ca-certificates.crt" \ - -sigin codesignatures/win/"$infile_base".pem + -sigin codesignatures/win/"${bin_base}".pem done + + # Move installer to outdir + cd "${WORKDIR}" + find . -name "*setup.exe" -print0 \ + | xargs -0r mv --target-directory="${OUTDIR}" + + # Make .zip from binaries + find "${DISTNAME}" -print0 \ + | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" + find "${DISTNAME}" \ + | sort \ + | zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" && exit 1 ) ;; *darwin*) - # Apply detached codesignatures to dist/ (in-place) - signapple apply dist/Bitcoin-Qt.app codesignatures/osx/dist + case "$HOST" in + arm64*) ARCH="arm64" ;; + x86_64*) ARCH="x86_64" ;; + esac + + # Apply detached codesignatures (in-place) + signapple apply dist/Bitcoin-Qt.app codesignatures/osx/"${HOST}"/dist/Bitcoin-Qt.app + find "${DISTNAME}" -wholename "*/bin/*" -type f | while read -r bin + do + signapple apply "${bin}" "codesignatures/osx/${HOST}/${bin}.${ARCH}sign" + done # Make a .zip from dist/ cd dist/ @@ -91,6 +121,14 @@ mkdir -p "$DISTSRC" | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" find . | sort \ | zip -X@ "${OUTDIR}/${DISTNAME}-${HOST}.zip" + cd .. + + # Make a .tar.gz from bins + find "${DISTNAME}" -print0 \ + | sort --zero-terminated \ + | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ + | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \ + || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 ) ;; *) exit 1 @@ -105,7 +143,7 @@ mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR" \ ( cd /outdir-base { - echo "$UNSIGNED_TARBALL" + echo "$CODESIGNING_TARBALL" echo "$CODESIGNATURE_GIT_ARCHIVE" find "$ACTUAL_OUTDIR" -type f } | xargs realpath --relative-base="$PWD" \ diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 479cdc6f33e..4e7e9552182 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -15,13 +15,14 @@ (gnu packages mingw) (gnu packages pkg-config) ((gnu packages python) #:select (python-minimal)) - ((gnu packages python-build) #:select (python-tomli)) + ((gnu packages python-build) #:select (python-tomli python-poetry-core)) ((gnu packages python-crypto) #:select (python-asn1crypto)) ((gnu packages tls) #:select (openssl)) ((gnu packages version-control) #:select (git-minimal)) (guix build-system cmake) (guix build-system gnu) (guix build-system python) + (guix build-system pyproject) (guix build-system trivial) (guix download) (guix gexp) @@ -381,10 +382,10 @@ specific moment in time, whitelisting and revocation checks.") (license license:expat)))) (define-public python-signapple - (let ((commit "62155712e7417aba07565c9780a80e452823ae6a")) + (let ((commit "85bfcecc33d2773bc09bc318cec0614af2c8e287")) (package (name "python-signapple") - (version (git-version "0.1" "1" commit)) + (version (git-version "0.2.0" "1" commit)) (source (origin (method git-fetch) @@ -394,13 +395,14 @@ specific moment in time, whitelisting and revocation checks.") (file-name (git-file-name name commit)) (sha256 (base32 - "1nm6rm4h4m7kbq729si4cm8rzild62mk4ni8xr5zja7l33fhv3gb")))) - (build-system python-build-system) + "17yqjll8nw83q6dhgqhkl7w502z5vy9sln8m6mlx0f1c10isg8yg")))) + (build-system pyproject-build-system) (propagated-inputs (list python-asn1crypto python-oscrypto python-certvalidator python-elfesteem)) + (native-inputs (list python-poetry-core)) ;; There are no tests, but attempting to run python setup.py test leads to ;; problems, just disable the test (arguments '(#:tests? #f)) diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 097a7c35ee4..89094403b7f 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -6,26 +6,57 @@ export LC_ALL=C set -e -ROOTDIR=dist -BUNDLE="${ROOTDIR}/Bitcoin-Qt.app" -BINARY="${BUNDLE}/Contents/MacOS/Bitcoin-Qt" SIGNAPPLE=signapple TEMPDIR=sign.temp -ARCH=$(${SIGNAPPLE} info ${BINARY} | head -n 1 | cut -d " " -f 1) -OUT="signature-osx-${ARCH}.tar.gz" -OUTROOT=osx/dist -if [ -z "$1" ]; then - echo "usage: $0 " - echo "example: $0 " +BUNDLE_ROOT=dist +BUNDLE_NAME="Bitcoin-Qt.app" +UNSIGNED_BUNDLE="${BUNDLE_ROOT}/${BUNDLE_NAME}" +UNSIGNED_BINARY="${UNSIGNED_BUNDLE}/Contents/MacOS/Bitcoin-Qt" + +ARCH=$(${SIGNAPPLE} info ${UNSIGNED_BINARY} | head -n 1 | cut -d " " -f 1) + +OUTDIR="osx/${ARCH}-apple-darwin" +OUTROOT="${TEMPDIR}/${OUTDIR}" + +OUT="signature-osx-${ARCH}.tar.gz" + +if [ "$#" -ne 3 ]; then + echo "usage: $0 " exit 1 fi rm -rf ${TEMPDIR} mkdir -p ${TEMPDIR} -${SIGNAPPLE} sign -f --detach "${TEMPDIR}/${OUTROOT}" "$@" "${BUNDLE}" --hardened-runtime +stty -echo +printf "Enter the passphrase for %s: " "$1" +read cs_key_pass +printf "\n" +printf "Enter the passphrase for %s: " "$2" +read api_key_pass +printf "\n" +stty echo -tar -C "${TEMPDIR}" -czf "${OUT}" . +# Sign and notarize app bundle +${SIGNAPPLE} sign -f --hardened-runtime --detach "${OUTROOT}/${BUNDLE_ROOT}" --passphrase "${cs_key_pass}" "$1" "${UNSIGNED_BUNDLE}" +${SIGNAPPLE} apply "${UNSIGNED_BUNDLE}" "${OUTROOT}/${BUNDLE_ROOT}/${BUNDLE_NAME}" +${SIGNAPPLE} notarize --detach "${OUTROOT}/${BUNDLE_ROOT}" --passphrase "${api_key_pass}" "$2" "$3" "${UNSIGNED_BUNDLE}" + +# Sign each binary +find . -maxdepth 3 -wholename "*/bin/*" -type f -exec realpath --relative-to=. {} \; | while read -r bin +do + bin_dir=$(dirname "${bin}") + bin_name=$(basename "${bin}") + ${SIGNAPPLE} sign -f --hardened-runtime --detach "${OUTROOT}/${bin_dir}" --passphrase "${cs_key_pass}" "$1" "${bin}" + ${SIGNAPPLE} apply "${bin}" "${OUTROOT}/${bin_dir}/${bin_name}.${ARCH}sign" +done + +# Notarize the binaries +# Binaries cannot have stapled notarizations so this does not actually generate any output +binaries_dir=$(dirname "$(find . -maxdepth 2 -wholename '*/bin' -type d -exec realpath --relative-to=. {} \;)") +${SIGNAPPLE} notarize --passphrase "${api_key_pass}" "$2" "$3" "${binaries_dir}" + +tar -C "${TEMPDIR}" -czf "${OUT}" "${OUTDIR}" rm -rf "${TEMPDIR}" echo "Created ${OUT}" diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh index 82fcf2d4068..4ec726534c7 100755 --- a/contrib/windeploy/detached-sig-create.sh +++ b/contrib/windeploy/detached-sig-create.sh @@ -8,9 +8,9 @@ if [ -z "$OSSLSIGNCODE" ]; then OSSLSIGNCODE=osslsigncode fi -if [ -z "$1" ]; then - echo "usage: $0 " - echo "example: $0 -key codesign.key" +if [ "$#" -ne 1 ]; then + echo "usage: $0 " + echo "example: $0 codesign.key" exit 1 fi @@ -22,12 +22,22 @@ OUTSUBDIR="${OUTDIR}/win" TIMESERVER=http://timestamp.comodoca.com CERTFILE="win-codesign.cert" +stty -echo +printf "Enter the passphrase for %s: " "$1" +read cs_key_pass +printf "\n" +stty echo + + mkdir -p "${OUTSUBDIR}" -# shellcheck disable=SC2046 -basename -a $(ls -1 "${SRCDIR}"/*-unsigned.exe) | while read UNSIGNED; do - echo Signing "${UNSIGNED}" - "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@" - "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}" +find ${SRCDIR} -wholename "*.exe" -type f -exec realpath --relative-to=. {} \; | while read -r bin +do + echo Signing "${bin}" + bin_base="$(realpath --relative-to=${SRCDIR} "${bin}")" + mkdir -p "$(dirname ${WORKDIR}/"${bin_base}")" + "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 -in "${bin}" -out "${WORKDIR}/${bin_base}" -key "$1" -pass "${cs_key_pass}" + mkdir -p "$(dirname ${OUTSUBDIR}/"${bin_base}")" + "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${bin_base}" -out "${OUTSUBDIR}/${bin_base}.pem" && rm "${WORKDIR}/${bin_base}" done rm -f "${OUT}" diff --git a/doc/release-process.md b/doc/release-process.md index bf466542840..1c5810d0238 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -166,8 +166,8 @@ Then open a Pull Request to the [guix.sigs repository](https://github.com/bitcoi In the `guix-build-${VERSION}/output/x86_64-apple-darwin` and `guix-build-${VERSION}/output/arm64-apple-darwin` directories: - tar xf bitcoin-osx-unsigned.tar.gz - ./detached-sig-create.sh /path/to/codesign.p12 + tar xf bitcoin-${VERSION}-${ARCH}-apple-darwin-codesigning.tar.gz + ./detached-sig-create.sh /path/to/codesign.p12 /path/to/AuthKey_foo.p8 uuid Enter the keychain password and authorize the signature signature-osx.tar.gz will be created @@ -175,8 +175,8 @@ In the `guix-build-${VERSION}/output/x86_64-apple-darwin` and `guix-build-${VERS In the `guix-build-${VERSION}/output/x86_64-w64-mingw32` directory: - tar xf bitcoin-win-unsigned.tar.gz - ./detached-sig-create.sh -key /path/to/codesign.key + tar xf bitcoin-${VERSION}-win64-codesigning.tar.gz + ./detached-sig-create.sh /path/to/codesign.key Enter the passphrase for the key when prompted signature-win.tar.gz will be created