Skip to content

Commit 1e77012

Browse files
committed
Update start.sh
Added Signature verification
1 parent 680184c commit 1e77012

File tree

1 file changed

+126
-3
lines changed

1 file changed

+126
-3
lines changed

modules/autoupdate/start.sh

Lines changed: 126 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,102 @@ YELLOW='\033[0;33m'; RED='\033[0;31m'
1212
MAGENTA='\033[0;35m'; CYAN='\033[0;36m'
1313
NC='\033[0m'
1414

15+
# ============================================================================
16+
# CRYPTOGRAPHIC SIGNATURE VERIFICATION
17+
# ============================================================================
18+
# Ed25519 Public Key for verifying update signatures
19+
# This key is embedded in the script to prevent tampering
20+
# Generate new keypair: Run API with SIGNING_PRIVATE_KEY not set, then generate
21+
# PUBLIC_KEY_BASE64="YOUR_PUBLIC_KEY_HERE"
22+
PUBLIC_KEY_BASE64="5MpxNNMkROJLixsSTk/PDBAFRF3bP+zr3U0lzzK/py4="
23+
24+
# Verify signature of downloaded update
25+
# Usage: verify_signature <file_path> <signature_base64> <expected_hash>
26+
# Returns: 0 if valid, 1 if invalid or verification unavailable
27+
verify_signature() {
28+
local file_path="$1"
29+
local signature_b64="$2"
30+
local expected_hash="$3"
31+
32+
# Skip verification if no public key is configured
33+
if [[ -z "$PUBLIC_KEY_BASE64" ]]; then
34+
echo -e "${YELLOW}[AutoUpdate] ⚠ Signature verification skipped - no public key configured${NC}"
35+
return 0
36+
fi
37+
38+
# Check if openssl is available
39+
if ! command -v openssl >/dev/null 2>&1; then
40+
echo -e "${YELLOW}[AutoUpdate] ⚠ Signature verification skipped - openssl not available${NC}"
41+
return 0
42+
fi
43+
44+
echo -e "${CYAN}[AutoUpdate] 🔐 Verifying cryptographic signature...${NC}"
45+
46+
# Verify file hash first
47+
local actual_hash
48+
actual_hash=$(sha256sum "$file_path" | cut -d' ' -f1)
49+
50+
if [[ "$actual_hash" != "$expected_hash" ]]; then
51+
echo -e "${RED}[AutoUpdate] ✗ Hash mismatch!${NC}"
52+
echo -e "${RED}[AutoUpdate] Expected: $expected_hash${NC}"
53+
echo -e "${RED}[AutoUpdate] Actual: $actual_hash${NC}"
54+
return 1
55+
fi
56+
57+
echo -e "${GREEN}[AutoUpdate] ✓ Hash verified: ${actual_hash:0:16}...${NC}"
58+
59+
# Decode public key and signature to temp files
60+
local temp_dir
61+
temp_dir=$(mktemp -d)
62+
local pub_key_file="$temp_dir/public.pem"
63+
local sig_file="$temp_dir/signature.bin"
64+
local hash_file="$temp_dir/hash.bin"
65+
66+
# Convert base64 public key to PEM format for Ed25519
67+
# Ed25519 public key is 32 bytes, we need to wrap it in proper ASN.1 structure
68+
{
69+
echo "-----BEGIN PUBLIC KEY-----"
70+
# Add Ed25519 OID prefix (MCowBQYDK2VwAyEA) + base64 public key
71+
echo "MCowBQYDK2VwAyEA$(echo "$PUBLIC_KEY_BASE64")" | fold -w 64
72+
echo "-----END PUBLIC KEY-----"
73+
} > "$pub_key_file"
74+
75+
# Decode signature from base64
76+
echo "$signature_b64" | base64 -d > "$sig_file" 2>/dev/null || {
77+
echo -e "${RED}[AutoUpdate] ✗ Failed to decode signature${NC}"
78+
rm -rf "$temp_dir"
79+
return 1
80+
}
81+
82+
# Create hash file (the signature is over the hash, not the file directly)
83+
# Convert hex to binary - use xxd if available, otherwise use printf
84+
if command -v xxd >/dev/null 2>&1; then
85+
echo -n "$expected_hash" | xxd -r -p > "$hash_file"
86+
else
87+
# Fallback: convert hex to binary using printf
88+
local hex="$expected_hash"
89+
local i
90+
> "$hash_file" # Create empty file
91+
for ((i=0; i<${#hex}; i+=2)); do
92+
printf "\x${hex:$i:2}" >> "$hash_file"
93+
done
94+
fi
95+
96+
# Verify signature using openssl (Ed25519)
97+
if openssl pkeyutl -verify -pubin -inkey "$pub_key_file" \
98+
-sigfile "$sig_file" -in "$hash_file" -rawin 2>/dev/null; then
99+
echo -e "${GREEN}[AutoUpdate] ✓ Signature verified - update is authentic${NC}"
100+
rm -rf "$temp_dir"
101+
return 0
102+
else
103+
echo -e "${RED}[AutoUpdate] ✗ Signature verification FAILED!${NC}"
104+
echo -e "${RED}[AutoUpdate] The update may have been tampered with.${NC}"
105+
echo -e "${RED}[AutoUpdate] Update will NOT be applied for security reasons.${NC}"
106+
rm -rf "$temp_dir"
107+
return 1
108+
fi
109+
}
110+
15111
# Header function
16112
header() {
17113
echo -e "${BLUE}───────────────────────────────────────────────${NC}"
@@ -270,13 +366,24 @@ apply_update() {
270366
# Extract download URL from response
271367
local download_url
272368
download_url=$(echo "$diff_response" | grep -o '"download_url":"[^"]*"' | cut -d'"' -f4)
273-
369+
274370
if [[ -z "$download_url" ]]; then
275371
echo -e "${RED}[AutoUpdate] No download URL found in diff response${NC}"
276372
rm -f "$temp_diff_file"
277373
return 1
278374
fi
279-
375+
376+
# Extract signature information for verification
377+
local signature checksum
378+
signature=$(echo "$diff_response" | grep -o '"signature":"[^"]*"' | cut -d'"' -f4 || echo "")
379+
checksum=$(echo "$diff_response" | grep -o '"checksum":"[^"]*"' | cut -d'"' -f4 || echo "")
380+
381+
if [[ -n "$signature" && -n "$checksum" ]]; then
382+
echo -e "${CYAN}[AutoUpdate] 🔐 Signed update detected${NC}"
383+
elif [[ -n "$PUBLIC_KEY_BASE64" ]]; then
384+
echo -e "${YELLOW}[AutoUpdate] ⚠ Update is unsigned but signature verification is enabled${NC}"
385+
fi
386+
280387
# Extract file change information for logging
281388
local total_changes files_added files_modified files_removed
282389
total_changes=$(echo "$diff_response" | grep -o '"total_changes":[0-9]*' | cut -d':' -f2)
@@ -321,7 +428,23 @@ apply_update() {
321428
rm -f "$zip_file"
322429
return 1
323430
fi
324-
431+
432+
# Verify signature if available
433+
if [[ -n "$signature" && -n "$checksum" ]]; then
434+
if ! verify_signature "$zip_file" "$signature" "$checksum"; then
435+
echo -e "${RED}[AutoUpdate] ✗ Signature verification failed - aborting update${NC}"
436+
rm -f "$zip_file" "$temp_diff_file"
437+
return 1
438+
fi
439+
elif [[ -n "$PUBLIC_KEY_BASE64" && "$PUBLIC_KEY_BASE64" != "YOUR_PUBLIC_KEY_HERE" ]]; then
440+
# Public key is configured but update is unsigned - reject for security
441+
echo -e "${RED}[AutoUpdate] ✗ Update is unsigned but signature verification is required${NC}"
442+
echo -e "${RED}[AutoUpdate] ✗ Aborting update for security reasons${NC}"
443+
echo -e "${YELLOW}[AutoUpdate] To allow unsigned updates, remove or comment out PUBLIC_KEY_BASE64${NC}"
444+
rm -f "$zip_file" "$temp_diff_file"
445+
return 1
446+
fi
447+
325448
echo -e "${WHITE}[AutoUpdate] Extracting and applying updates...${NC}"
326449

327450
# Extract to temporary directory

0 commit comments

Comments
 (0)