diff --git a/scripts/Base/empty_trustsore.sh b/scripts/Base/empty_trustsore.sh new file mode 100644 index 0000000..8a7857c --- /dev/null +++ b/scripts/Base/empty_trustsore.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# Usage: +# ./create-truststore.sh [CA_CERT [TRUSTSTORE [ALIAS]]] +# ./create-truststore.sh --verify [CA_CERT [TRUSTSTORE [ALIAS]]] +# Defaults may be overridden with CERT_DIR, CA_CERT, TRUSTSTORE, CA_ALIAS, JAVA_BIN. +# Requires Java 8+; javac is required on Java 8-10. +# Java 11+ supports source-file mode when the jdk.compiler module is available. +set -euo pipefail + +CERT_DIR="${CERT_DIR:-/site/var/spring/key}" +CA_CERT="${CA_CERT:-${CERT_DIR}/local-root-ca.crt}" +TRUSTSTORE="${TRUSTSTORE:-${CERT_DIR}/truststore-empty.jks}" +CA_ALIAS="${CA_ALIAS:-local-root-ca}" + +MODE=create +if [[ "${1:-}" == --verify ]]; then + MODE=verify + shift +fi +CA_CERT="${1:-${CA_CERT}}" +TRUSTSTORE="${2:-${TRUSTSTORE}}" +CA_ALIAS="${3:-${CA_ALIAS}}" +if (( $# > 3 )); then + echo 'Usage: create-truststore.sh [--verify] [CA_CERT [TRUSTSTORE [ALIAS]]]' >&2 + exit 2 +fi + +if [[ ! -r "${CA_CERT}" ]]; then + echo "ERROR: CA certificate not readable: ${CA_CERT}" >&2 + exit 1 +fi +if [[ "${MODE}" == create && -e "${TRUSTSTORE}" ]]; then + echo "ERROR: TrustStore already exists: ${TRUSTSTORE}" >&2 + exit 1 +fi +if [[ "${MODE}" == verify && ! -r "${TRUSTSTORE}" ]]; then + echo "ERROR: TrustStore not readable: ${TRUSTSTORE}" >&2 + exit 1 +fi + +JAVA_BIN="${JAVA_BIN:-$(which java 2>/dev/null || true)}" +if [[ -z "${JAVA_BIN}" || ! -x "${JAVA_BIN}" ]]; then + echo 'ERROR: java not found (set JAVA_BIN or add java to PATH)' >&2 + exit 1 +fi + +JAVA_MAJOR="$("${JAVA_BIN}" -version 2>&1 | awk -F '"' '/version/ {split($2, v, "."); print (v[1] == "1" ? v[2] : v[1]); exit}')" +if [[ ! "${JAVA_MAJOR}" =~ ^[0-9]+$ || "${JAVA_MAJOR}" -lt 8 ]]; then + echo 'ERROR: cannot determine Java version or Java is older than 8' >&2 + exit 1 +fi + +WORK_DIR="$(mktemp -d)" +trap 'rm -rf -- "${WORK_DIR}"' EXIT +SOURCE="${WORK_DIR}/CreateTrustStore.java" + +cat > "${SOURCE}" <<'JAVA' +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +public class CreateTrustStore { + public static void main(String[] args) throws Exception { + String mode = args[0]; + String certPath = args[1]; + String storePath = args[2]; + String alias = args[3]; + char[] password = new char[0]; + + Certificate ca; + try (InputStream in = Files.newInputStream(Paths.get(certPath))) { + ca = CertificateFactory.getInstance("X.509").generateCertificate(in); + } + + KeyStore store = KeyStore.getInstance("JKS"); + if ("create".equals(mode)) { + store.load(null, password); + store.setCertificateEntry(alias, ca); + try (OutputStream out = Files.newOutputStream( + Paths.get(storePath), StandardOpenOption.CREATE_NEW)) { + store.store(out, password); + } + } else if (!"verify".equals(mode)) { + throw new IllegalArgumentException("Unknown mode: " + mode); + } + + try (InputStream in = Files.newInputStream(Paths.get(storePath))) { + store.load(in, password); + } + if (!store.isCertificateEntry(alias) || !ca.equals(store.getCertificate(alias))) { + throw new IllegalStateException("CA certificate/alias mismatch"); + } + System.out.println("OK: JKS verified with empty password; alias=" + alias); + } +} +JAVA + +umask 077 +# Prefer javac from the selected Java installation to avoid mixing JDK versions. +# For Java 11+ source-file mode is preferred, especially on JRE-only systems. +resolve_javac() { + local java_real java_dir candidate + java_real="$(readlink -f -- "${JAVA_BIN}" 2>/dev/null || printf '%s' "${JAVA_BIN}")" + java_dir="$(dirname -- "${java_real}")" + candidate="${JAVAC_BIN:-${java_dir}/javac}" + if [[ -x "${candidate}" ]]; then + printf '%s\n' "${candidate}" + return 0 + fi + # A java executable in PATH may be a wrapper; javac from PATH is usable + # only when it belongs to the same major Java version. + if [[ -z "${JAVAC_BIN:-}" ]]; then + candidate="$(which javac 2>/dev/null || true)" + if [[ -n "${candidate}" && -x "${candidate}" ]]; then + local compiler_major + compiler_major="$("${candidate}" -version 2>&1 | awk '{split($2,v,"."); print (v[1] == "1" ? v[2] : v[1])}')" + if [[ "${compiler_major}" == "${JAVA_MAJOR}" ]]; then + printf '%s\n' "${candidate}" + return 0 + fi + fi + fi + return 1 +} + +run_compiled() { + local compiler + compiler="$(resolve_javac)" || { + echo "ERROR: Java ${JAVA_MAJOR}: javac from the matching JDK is required" >&2 + return 1 + } + "${compiler}" -d "${WORK_DIR}" "${SOURCE}" + "${JAVA_BIN}" -cp "${WORK_DIR}" CreateTrustStore "${MODE}" "${CA_CERT}" "${TRUSTSTORE}" "${CA_ALIAS}" +} + +if (( JAVA_MAJOR >= 11 )); then + # A runtime image can omit jdk.compiler: fall back to javac if available. + if "${JAVA_BIN}" --list-modules 2>/dev/null | grep -q '^jdk.compiler@'; then + "${JAVA_BIN}" "${SOURCE}" "${MODE}" "${CA_CERT}" "${TRUSTSTORE}" "${CA_ALIAS}" + else + run_compiled + fi +else + run_compiled +fi + +if [[ "${MODE}" == create ]]; then + chmod 640 -- "${TRUSTSTORE}" + echo "TrustStore created: ${TRUSTSTORE}" +fi \ No newline at end of file