Repository navigation
Expand file tree
/
Copy pathcheck_jwt_token.sh
More file actions
executable file
·147 lines (118 loc) · 3.34 KB
/
Copy pathcheck_jwt_token.sh
File metadata and controls
executable file
·147 lines (118 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env bash
set -euo pipefail
# ---- Args ----
if [[ $# -ne 2 ]]; then
echo "Usage: $0 jwt_token quote_hex" >&2
exit 2
fi
JWT="$1"
QUOTE_HEX="$2"
# Basic validation of quote hex
if ! [[ "$QUOTE_HEX" =~ ^[0-9a-fA-F]+$ ]]; then
echo "Error: quote_hex is not valid hex" >&2
exit 2
fi
if (( ${#QUOTE_HEX} % 2 != 0 )); then
echo "Error: quote_hex must contain an even number of hex digits" >&2
exit 2
fi
# ---- Compute sha256(quote binary), where quote is provided as hex ----
QUOTE_HASH_ACTUAL="$(
printf '%s' "$QUOTE_HEX" | xxd -r -p | sha256sum | awk '{print $1}'
)"
#PUBKEY_HEX='5c8b1d8541733c5cf9593a5f6b608105a1315514a584dde8496471a2e90c88aa'
PUBKEY_HEX=$(curl -s https://raw.githubusercontent.com/proofofcloud/trust-server/refs/heads/main/public_info/public_key.txt)
if ! [[ "$PUBKEY_HEX" =~ ^[0-9a-fA-F]{64}$ ]]; then
echo "Error: fetched public key is not a valid 32-byte hex string" >&2
exit 1
fi
echo 'Shared pubkey: ' $PUBKEY_HEX
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
IFS='.' read -r HDR PAY SIG <<< "$JWT"
if [ -z "${HDR:-}" ] || [ -z "${PAY:-}" ] || [ -z "${SIG:-}" ]; then
echo "Invalid JWT format" >&2
exit 1
fi
# Build Ed25519 SPKI public key PEM from raw 32-byte hex key
python3 - "$PUBKEY_HEX" > "$tmpdir/pubkey.pem" <<'PY'
import sys, base64, textwrap
pk_hex = sys.argv[1]
pk = bytes.fromhex(pk_hex)
if len(pk) != 32:
raise SystemExit(f"Public key must be 32 bytes, got {len(pk)}")
# ASN.1 DER SubjectPublicKeyInfo prefix for Ed25519:
# 30 2a
# 30 05
# 06 03 2b 65 70
# 03 21 00
der = bytes.fromhex("302a300506032b6570032100") + pk
b64 = base64.b64encode(der).decode()
print("-----BEGIN PUBLIC KEY-----")
for i in range(0, len(b64), 64):
print(b64[i:i+64])
print("-----END PUBLIC KEY-----")
PY
# Exact signed data is "<base64url(header)>.<base64url(payload)>"
printf '%s.%s' "$HDR" "$PAY" > "$tmpdir/msg.bin"
# Decode JWT signature from base64url
python3 - "$SIG" > "$tmpdir/sig.bin" <<'PY'
import sys, base64
s = sys.argv[1]
s += "=" * ((4 - len(s) % 4) % 4)
sys.stdout.buffer.write(base64.urlsafe_b64decode(s))
PY
# Optional: check alg field
ALG="$(python3 - "$HDR" <<'PY'
import sys, base64, json
s = sys.argv[1]
s += "=" * ((4 - len(s) % 4) % 4)
obj = json.loads(base64.urlsafe_b64decode(s))
print(obj.get("alg", ""))
PY
)"
if [ "$ALG" != "EdDSA" ]; then
echo "Unexpected JWT alg: $ALG" >&2
exit 1
fi
# Verify signature
if ! OUT=$(openssl pkeyutl \
-verify \
-pubin \
-inkey "$tmpdir/pubkey.pem" \
-rawin \
-in "$tmpdir/msg.bin" \
-sigfile "$tmpdir/sig.bin" \
2>&1); then
echo "$OUT"
exit 1
fi
echo "Signature: OK"
# Extract quote_hash and timestamp
read -r QUOTE_HASH_FROM_JWT TIMESTAMP_FROM_JWT < <(
python3 - "$PAY" <<'PY'
import sys, base64, json
s = sys.argv[1]
s += "=" * ((4 - len(s) % 4) % 4)
obj = json.loads(base64.urlsafe_b64decode(s))
print(obj["quote_hash"], obj["timestamp"])
PY
)
if [[ "$QUOTE_HASH_ACTUAL" != "$QUOTE_HASH_FROM_JWT" ]]; then
echo "Error: quote hash mismatch" >&2
exit 1
fi
echo "Quote hash verified OK"
# check the timestamp
NOW_TS=$(date +%s)
DIFF=$(( NOW_TS - TIMESTAMP_FROM_JWT ))
if (( $DIFF < 0 )); then
echo "Error: Timestamp in the future: $TIMESTAMP_FROM_JWT"
exit 1
fi
if (( $DIFF > 3600*24*7 )); then
echo "Error: Timestamp too old: $TIMESTAMP_FROM_JWT"
echo "Time elapsed (s) : $DIFF"
exit 1
fi
echo "Timestamp is OK"