Skip to content

Commit 1b22039

Browse files
committed
ci: sync OS CA certs and AIA intermediates into GraalVM JDK before native compile
GraalVM native images embed the JDK cacerts at build time and cannot chase AIA URLs at runtime. When a server omits intermediate CAs from its TLS handshake, the native binary fails with HTTP 0 (connection error). The new step runs before native:compile-no-fork on every platform: - Part 1: imports root CAs from the OS trust store (macOS Keychain / Linux /etc/ssl/certs) so the binary trusts CAs added after GraalVM 21 was cut. - Part 2: reads the AIA CA Issuers URL from the server leaf cert, downloads the missing intermediate in DER format, and imports it. This self-heals when the server rotates to a new intermediate (e.g. WE1 → WE2) without requiring a manual cert update.
1 parent b479088 commit 1b22039

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,53 @@ jobs:
4747
java-version: '21'
4848
distribution: 'graalvm'
4949
cache: 'maven'
50+
- name: Sync OS CA certificates into GraalVM JDK
51+
shell: bash
52+
run: |
53+
CACERTS="$JAVA_HOME/lib/security/cacerts"
54+
55+
# 1. Import root CAs from the OS trust store
56+
if [[ "$RUNNER_OS" == "macOS" ]]; then
57+
security export -t certs -f pemseq \
58+
-k /System/Library/Keychains/SystemRootCertificates.keychain \
59+
> /tmp/os-roots.pem
60+
elif [[ "$RUNNER_OS" == "Linux" ]]; then
61+
cat /etc/ssl/certs/*.pem > /tmp/os-roots.pem 2>/dev/null || true
62+
fi
63+
if [[ -f /tmp/os-roots.pem ]]; then
64+
awk '/-----BEGIN CERTIFICATE-----/{n++; close(f); f="/tmp/ca-"n".pem"} {print > f}' \
65+
/tmp/os-roots.pem
66+
imported=0
67+
for f in /tmp/ca-*.pem; do
68+
[[ -s "$f" ]] || continue
69+
hash=$(openssl x509 -noout -hash -in "$f" 2>/dev/null) || continue
70+
keytool -importcert -noprompt -trustcacerts \
71+
-alias "os-root-${hash}" \
72+
-keystore "$CACERTS" -storepass changeit \
73+
-file "$f" 2>/dev/null && ((imported++)) || true
74+
done
75+
echo "Imported $imported root CAs from OS"
76+
fi
77+
78+
# 2. Fetch any intermediate CAs the server omits from its TLS chain (via AIA).
79+
# GraalVM native images cannot chase AIA at runtime; bake the intermediates in.
80+
AIA_URL=$(echo | openssl s_client -connect api.qtsurfer.net:443 \
81+
-servername api.qtsurfer.net 2>/dev/null \
82+
| openssl x509 -noout -text 2>/dev/null \
83+
| grep "CA Issuers" | grep -o 'http[^ ]*' | head -1)
84+
if [[ -n "$AIA_URL" ]]; then
85+
curl -sf "$AIA_URL" -o /tmp/intermediate.der
86+
openssl x509 -inform der -in /tmp/intermediate.der -out /tmp/intermediate.pem 2>/dev/null \
87+
|| cp /tmp/intermediate.der /tmp/intermediate.pem
88+
hash=$(openssl x509 -noout -hash -in /tmp/intermediate.pem 2>/dev/null)
89+
subj=$(openssl x509 -noout -subject -in /tmp/intermediate.pem 2>/dev/null)
90+
keytool -importcert -noprompt -trustcacerts \
91+
-alias "intermediate-${hash}" \
92+
-keystore "$CACERTS" -storepass changeit \
93+
-file /tmp/intermediate.pem 2>/dev/null \
94+
&& echo "Imported intermediate CA: ${subj}" \
95+
|| echo "Intermediate already trusted: ${subj}"
96+
fi
5097
- name: Build native binary
5198
run: mvn -B -Pnative -DskipTests package native:compile-no-fork
5299
- name: Upload native binary

0 commit comments

Comments
 (0)