diff --git a/dockerfiles/LocalKeySignatureScript.sh b/dockerfiles/LocalKeySignatureScript.sh index 210cb3f444..d4d4ae265c 100755 --- a/dockerfiles/LocalKeySignatureScript.sh +++ b/dockerfiles/LocalKeySignatureScript.sh @@ -1,34 +1,101 @@ #!/bin/bash +set -euo pipefail -set -e +# Parameters +BINARY_PATH="${1:-main}" +SIGNER_SOURCE_PATH="${2:-/home/obscuro/go-obscuro/tools/enclavesigner/main}" +SIGNER_TOOL_PATH="/tmp/enclavesigner" + +# Private key path inside the build container (file must exist in the build context) +LOCAL_SIGNING_KEY_PATH="${LOCAL_SIGNING_KEY_PATH:-/home/obscuro/go-obscuro/tools/enclavesigner/sgx_enclave_signing_key_rsa3072_e3.pem}" TEMP_DIR="/tmp/sgx_local_signing" -DOCKER_SIGNATURE_PATH="/tmp/signature.b64" -DOCKER_MODULUS_PATH="/tmp/modulus.b64" +SIG_B64_PATH="/tmp/signature.b64" +MOD_B64_PATH="/tmp/modulus.b64" + +echo "====== LOCAL KEY SIGNATURE REPLACEMENT (FILE-BASED KEY, NO AZURE) ======" +echo "Using private key: $LOCAL_SIGNING_KEY_PATH" + +echo "====== ENSURING DEPENDENCIES ======" +if ! command -v openssl >/dev/null 2>&1; then + apt-get update + apt-get install -y openssl ca-certificates + apt-get clean && rm -rf /var/lib/apt/lists/* +fi + +if [ ! -f "$LOCAL_SIGNING_KEY_PATH" ]; then + echo "ERROR: Private key file not found at: $LOCAL_SIGNING_KEY_PATH" + echo "Make sure you generated it on the host and that it is included in the Docker build context." + exit 1 +fi + +echo "====== BUILDING ENCLAVE SIGNER TOOL ======" +if [ -d "$SIGNER_SOURCE_PATH" ]; then + current_dir="$(pwd)" + cd "$SIGNER_SOURCE_PATH" + go build -o "$SIGNER_TOOL_PATH" . + cd "$current_dir" +else + echo "ERROR: Signer source path not found: $SIGNER_SOURCE_PATH" + exit 1 +fi + +echo "====== STEP 1: EXTRACT HASH FROM EGO-SIGNED ENCLAVE ======" +cp "$BINARY_PATH" "$BINARY_PATH.original" +hash_b64="$("$SIGNER_TOOL_PATH" extract_hash "$BINARY_PATH")" +echo "$hash_b64" > /tmp/hash.b64 +echo "Hash (Base64) extracted: $(echo "$hash_b64" | head -c 50)..." -main() { - DIGEST_B64="$1" +echo "====== STEP 2: SIGN USING EXISTING PRIVATE KEY ======" +mkdir -p "$TEMP_DIR" - mkdir -p "$TEMP_DIR" +# Optional sanity checks (fail fast if key is wrong) +bits="$(openssl rsa -in "$LOCAL_SIGNING_KEY_PATH" -text -noout 2>/dev/null | awk '/Private-Key:/ {gsub("[()]", "", $2); print $2; exit}')" +exp="$(openssl rsa -in "$LOCAL_SIGNING_KEY_PATH" -text -noout 2>/dev/null | awk -F'[()]' '/publicExponent/ {print $2; exit}')" +if [ "${bits:-}" != "3072" ]; then + echo "ERROR: Expected RSA-3072 key, got: ${bits:-unknown}" + exit 1 +fi +if [ "${exp:-}" != "3" ]; then + echo "ERROR: Expected public exponent e=3, got: ${exp:-unknown}" + exit 1 +fi - # Generate RSA key - openssl genrsa -3 -out "$TEMP_DIR/private_key.pem" 3072 2>/dev/null +# Extract modulus (n) and encode as Base64 (raw bytes) +modulus_hex="$(openssl rsa -in "$LOCAL_SIGNING_KEY_PATH" -modulus -noout 2>/dev/null | cut -d'=' -f2)" +printf '%s' "$modulus_hex" | xxd -r -p > "$TEMP_DIR/modulus.bin" +modulus_b64="$(base64 -w 0 < "$TEMP_DIR/modulus.bin" 2>/dev/null || base64 < "$TEMP_DIR/modulus.bin" | tr -d '\n')" - # Extract modulus - modulus_hex=$(openssl rsa -in "$TEMP_DIR/private_key.pem" -modulus -noout 2>/dev/null | cut -d'=' -f2) - printf '%s' "$modulus_hex" | xxd -r -p > "$TEMP_DIR/modulus.bin" - modulus_b64=$(base64 -w 0 < "$TEMP_DIR/modulus.bin" 2>/dev/null || base64 < "$TEMP_DIR/modulus.bin" | tr -d '\n') - echo "modulus: $modulus_b64" +# Decode digest and sign using PKCS#1 v1.5 padding (raw RSA op) +printf '%s' "$hash_b64" | base64 -d > "$TEMP_DIR/digest.bin" +openssl rsautl -sign -pkcs -inkey "$LOCAL_SIGNING_KEY_PATH" -in "$TEMP_DIR/digest.bin" -out "$TEMP_DIR/signature.bin" >/dev/null 2>&1 +signature_b64="$(base64 -w 0 < "$TEMP_DIR/signature.bin" 2>/dev/null || base64 < "$TEMP_DIR/signature.bin" | tr -d '\n')" - # Sign - printf '%s' "$DIGEST_B64" | base64 -d > "$TEMP_DIR/digest.bin" - openssl rsautl -sign -in "$TEMP_DIR/digest.bin" -inkey "$TEMP_DIR/private_key.pem" -pkcs -out "$TEMP_DIR/signature.bin" 2>/dev/null - signature_b64=$(base64 -w 0 < "$TEMP_DIR/signature.bin" 2>/dev/null || base64 < "$TEMP_DIR/signature.bin" | tr -d '\n') - echo "sig: signature_b64" +printf '%s' "$signature_b64" > "$SIG_B64_PATH" +printf '%s' "$modulus_b64" > "$MOD_B64_PATH" - # Save outputs - printf '%s' "$signature_b64" > "$DOCKER_SIGNATURE_PATH" - printf '%s' "$modulus_b64" > "$DOCKER_MODULUS_PATH" +if [ ! -s "$SIG_B64_PATH" ] || [ ! -s "$MOD_B64_PATH" ]; then + echo "ERROR: Local signing failed (empty signature/modulus)." + exit 1 +fi + +echo "Signature (Base64): $(echo "$signature_b64" | head -c 50)..." +echo "Modulus (Base64): $(echo "$modulus_b64" | head -c 50)..." + +echo "====== STEP 3: REPLACE SIGNATURE IN ENCLAVE BINARY ======" +"$SIGNER_TOOL_PATH" replace "$BINARY_PATH" "$signature_b64" "$modulus_b64" "$BINARY_PATH.local_signed" 2>&1 + +echo "====== VERIFYING LOCALLY-SIGNED ENCLAVE ======" +"$SIGNER_TOOL_PATH" verify "$BINARY_PATH.local_signed" 2>&1 || { + echo "ERROR: Locally-signed enclave verification FAILED!" + exit 1 } -main "$@" \ No newline at end of file +mv "$BINARY_PATH.local_signed" "$BINARY_PATH" +echo "Enclave signature successfully replaced with LOCAL key signature" + +echo "====== FINAL VERIFICATION ======" +"$SIGNER_TOOL_PATH" verify "$BINARY_PATH" 2>&1 + +ls -la "$BINARY_PATH" +echo "Build completed successfully with LOCAL key signature integration" \ No newline at end of file diff --git a/dockerfiles/enclave.Dockerfile b/dockerfiles/enclave.Dockerfile index 2365ed9736..fc9439a25b 100644 --- a/dockerfiles/enclave.Dockerfile +++ b/dockerfiles/enclave.Dockerfile @@ -1,3 +1,5 @@ +# syntax=docker/dockerfile:1.6 + # for integration with the Azure Key Vault, it needs an azure "tenant id" and "subscription id" to be passed as build arguments # The build process when using these arguments is interactive. It requires logging in on Azure and approving the login request. ARG AZURE_TENANT_ID @@ -42,8 +44,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ # Sign the enclave executable RUN ego sign enclave.json -# Run the complete Azure HSM setup (builds signer tool, signs binary, or skips if not needed) -RUN /home/obscuro/go-obscuro/tools/enclavesigner/AzureHSMSignatureScript.sh main /home/obscuro/go-obscuro/tools/enclavesigner/main +# Use a local signing key provided from the host as a BuildKit secret (not baked into the image layers) +RUN --mount=type=secret,id=sgx_signing_key,target=/run/secrets/sgx_signing_key,required=true \ + LOCAL_SIGNING_KEY_PATH=/run/secrets/sgx_signing_key \ + /home/obscuro/go-obscuro/tools/enclavesigner/LocalKeySignatureScript.sh main /home/obscuro/go-obscuro/tools/enclavesigner/main # Trigger a new build stage and use the smaller ego version: FROM ghcr.io/edgelesssys/ego-deploy:v1.8.0 @@ -51,7 +55,7 @@ FROM ghcr.io/edgelesssys/ego-deploy:v1.8.0 # Copy just the binary for the enclave into this build stage COPY --from=build-enclave \ /home/obscuro/go-obscuro/go/enclave/main /home/obscuro/go-obscuro/go/enclave/main - + WORKDIR /home/obscuro/go-obscuro/go/enclave/main # simulation mode is ACTIVE by default diff --git a/tools/enclavesigner/README.MD b/tools/enclavesigner/README.MD index d212f7828f..b47c516412 100644 --- a/tools/enclavesigner/README.MD +++ b/tools/enclavesigner/README.MD @@ -1,3 +1,15 @@ Utility to verify and replace the signature of enclave binaries. -We use it during our build process to replace the signature on the enclave binaries with one generated securely. \ No newline at end of file +We use it during our build process to replace the signature on the enclave binaries with one generated securely. + + +## Signing using local key + +1. First generate the key using `GenerateImageSigningKey.sh`. +This will create a file ``sgx_enclave_signing_key_rsa3072_e3.pem`` in the current directory. +2. If you already have the key , just copy it to the local file system. +3. Build the enclave binaries using +```DOCKER_BUILDKIT=1 docker build \ +-f dockerfiles/enclave.Dockerfile \ +--secret id=sgx_signing_key,src=/absolute/path/to/sgx_enclave_signing_key_rsa3072_e3.pem \ +-t enclave:local-signed .``` \ No newline at end of file