The reviewed obfuscator that also performed standard hardening was never produced, so ABI-v2/v3 archives could not ship. Add an explicit, signature-bound signed-unobfuscated profile and accept ABI v3 (relay token) across the build-time validator, the audit gate, and the packager. The archive stays Ed25519-signed and ABI-pinned; private Rust symbol strings/paths/debug are retained by design and declared as hardening=op-auth-signed-unobfuscated-v1.
189 lines
5.2 KiB
Bash
Executable file
189 lines
5.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Package an already-hardened private op-auth ABI-v2 archive.
|
|
#
|
|
# This script intentionally does not strip or obfuscate an existing archive:
|
|
# those transformations must happen while rebuilding from private source, where
|
|
# the linker can prove the result. The script audits, signs, and stages new
|
|
# bytes in a fresh output directory without touching committed artifacts.
|
|
|
|
set -euo pipefail
|
|
|
|
script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd)
|
|
artifact=
|
|
target=
|
|
version=
|
|
source_revision=
|
|
build_id=
|
|
signing_key=
|
|
output_root=
|
|
profile=hardened
|
|
abi=2
|
|
|
|
usage() {
|
|
cat >&2 <<'EOF'
|
|
usage: package-op-auth-prebuilt.sh \
|
|
--artifact PATH --target TARGET --version VERSION \
|
|
--source-revision FULL_HEX_REVISION --build-id ID \
|
|
--signing-key ED25519_PRIVATE_KEY.pem --output-root NEW_DIRECTORY \
|
|
[--profile hardened|unobfuscated] [--abi 2|3]
|
|
EOF
|
|
}
|
|
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case "$1" in
|
|
--artifact|--target|--version|--source-revision|--build-id|--signing-key|--output-root|--profile|--abi)
|
|
[[ "$#" -ge 2 ]] || {
|
|
usage
|
|
exit 2
|
|
}
|
|
name=${1#--}
|
|
name=${name//-/_}
|
|
printf -v "$name" '%s' "$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
for required in artifact target version source_revision build_id signing_key output_root; do
|
|
if [[ -z "${!required}" ]]; then
|
|
printf 'error: --%s is required\n' "${required//_/-}" >&2
|
|
exit 2
|
|
fi
|
|
done
|
|
|
|
case "$target" in
|
|
aarch64-apple-darwin|aarch64-pc-windows-msvc|aarch64-unknown-linux-gnu|\
|
|
x86_64-apple-darwin|x86_64-pc-windows-msvc|x86_64-unknown-linux-gnu)
|
|
;;
|
|
*)
|
|
printf 'error: unsupported target: %s\n' "$target" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
case "$profile" in
|
|
hardened) hardening_profile=op-auth-hardened-v1 ;;
|
|
unobfuscated) hardening_profile=op-auth-signed-unobfuscated-v1 ;;
|
|
*)
|
|
printf 'error: --profile must be hardened or unobfuscated\n' >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
case "$abi" in
|
|
2|3) ;;
|
|
*)
|
|
printf 'error: --abi must be 2 or 3\n' >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
[[ -f "$artifact" ]] || {
|
|
printf 'error: artifact is not a regular file\n' >&2
|
|
exit 2
|
|
}
|
|
[[ -f "$signing_key" ]] || {
|
|
printf 'error: Ed25519 signing key is not a regular file\n' >&2
|
|
exit 2
|
|
}
|
|
[[ "$source_revision" =~ ^([0-9a-fA-F]{40}|[0-9a-fA-F]{64})$ ]] || {
|
|
printf 'error: source revision must be a full 40- or 64-digit hexadecimal revision\n' >&2
|
|
exit 2
|
|
}
|
|
[[ "$build_id" =~ ^[A-Za-z0-9._-]{1,128}$ ]] || {
|
|
printf 'error: build id must use 1-128 ASCII letters, digits, dot, underscore, or hyphen\n' >&2
|
|
exit 2
|
|
}
|
|
[[ "$version" =~ ^[0-9A-Za-z.+-]{1,64}$ ]] || {
|
|
printf 'error: version contains unsupported characters\n' >&2
|
|
exit 2
|
|
}
|
|
[[ ! -e "$output_root" ]] || {
|
|
printf 'error: output root already exists; refusing to overwrite it\n' >&2
|
|
exit 2
|
|
}
|
|
command -v openssl >/dev/null 2>&1 || {
|
|
printf 'error: openssl is required for Ed25519 provenance signing\n' >&2
|
|
exit 1
|
|
}
|
|
|
|
artifact_name=libop_auth.a
|
|
if [[ "$target" == *-pc-windows-msvc ]]; then
|
|
artifact_name=op_auth.lib
|
|
fi
|
|
|
|
temp_dir=$(mktemp -d "${TMPDIR:-/tmp}/op-auth-package.XXXXXX")
|
|
cleanup() {
|
|
rm -rf "$temp_dir"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
target_dir=$output_root/$target
|
|
mkdir -p "$target_dir"
|
|
cp "$artifact" "$target_dir/$artifact_name"
|
|
printf '%s\n' "$version" > "$target_dir/VERSION"
|
|
printf '%s\n' "$abi" > "$target_dir/ABI_VERSION"
|
|
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256=$(sha256sum "$target_dir/$artifact_name" | awk '{ print $1 }')
|
|
else
|
|
sha256=$(shasum -a 256 "$target_dir/$artifact_name" | awk '{ print $1 }')
|
|
fi
|
|
printf '%s\n' "$sha256" > "$target_dir/SHA256"
|
|
|
|
cat > "$target_dir/PROVENANCE" <<EOF
|
|
format=1
|
|
target=$target
|
|
artifact=$artifact_name
|
|
version=$version
|
|
abi=$abi
|
|
sha256=$sha256
|
|
hardening=$hardening_profile
|
|
source_revision=$source_revision
|
|
build_id=$build_id
|
|
EOF
|
|
|
|
openssl pkey -in "$signing_key" -pubout -out "$temp_dir/public.pem" >/dev/null
|
|
public_der_hex=$(
|
|
openssl pkey -pubin -in "$temp_dir/public.pem" -outform DER \
|
|
| od -An -v -tx1 \
|
|
| tr -d '[:space:]'
|
|
)
|
|
public_prefix=302a300506032b6570032100
|
|
case "$public_der_hex" in
|
|
"$public_prefix"[0-9a-f][0-9a-f][0-9a-f][0-9a-f]*)
|
|
;;
|
|
*)
|
|
printf 'error: signing key is not an Ed25519 private key\n' >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
public_key_hex=${public_der_hex#"$public_prefix"}
|
|
[[ ${#public_key_hex} -eq 64 ]] || {
|
|
printf 'error: unexpected Ed25519 public key encoding\n' >&2
|
|
exit 1
|
|
}
|
|
printf '%s\n' "$public_key_hex" > "$output_root/PROVENANCE_PUBKEY"
|
|
|
|
openssl pkeyutl -sign -rawin \
|
|
-inkey "$signing_key" \
|
|
-in "$target_dir/PROVENANCE" \
|
|
-out "$temp_dir/provenance.sig"
|
|
openssl pkeyutl -verify -rawin -pubin \
|
|
-inkey "$temp_dir/public.pem" \
|
|
-in "$target_dir/PROVENANCE" \
|
|
-sigfile "$temp_dir/provenance.sig" \
|
|
>/dev/null
|
|
od -An -v -tx1 "$temp_dir/provenance.sig" \
|
|
| tr -d '[:space:]' \
|
|
> "$target_dir/PROVENANCE.sig"
|
|
printf '\n' >> "$target_dir/PROVENANCE.sig"
|
|
|
|
OP_AUTH_PREBUILT_ROOT="$output_root" \
|
|
bash "$script_dir/check-op-auth-prebuilt.sh" --require-hardened
|
|
|
|
printf 'staged signed op-auth ABI-v2 artifact at %s\n' "$target_dir"
|