docs/verify-profile.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# verify-profile.sh — issue a throwaway leaf via the Vault PKI c2pa-leaf
# role and assert the strict KU/EKU/BasicConstraints profile. Fails
# non-zero on drift so this can be wired into CI.
#
# Requires:
# VAULT_ADDR, VAULT_TOKEN in env
# openssl, jq on PATH
# curl on PATH
#
# Optional:
# VAULT_CACERT path to CA bundle for self-signed Vault TLS
# MOUNT PKI mount path (default: pki-c2pa)
# ROLE role name (default: c2pa-leaf)
set -euo pipefail
MOUNT="${MOUNT:-pki-c2pa}"
ROLE="${ROLE:-c2pa-leaf}"
if [[ -z "${VAULT_ADDR:-}" || -z "${VAULT_TOKEN:-}" ]]; then
echo "FATAL: VAULT_ADDR and VAULT_TOKEN must be set" >&2
exit 2
fi
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
# 1. Generate a throwaway P-256 keypair + CSR.
openssl ecparam -name prime256v1 -genkey -noout -out "$WORK/leaf.key.pem" 2>/dev/null
openssl req -new -key "$WORK/leaf.key.pem" \
-subj "/CN=cuecrux daemon C2PA signer (verify-profile)" \
-out "$WORK/leaf.csr.pem" 2>/dev/null
# 2. POST the CSR to Vault, signed by the c2pa-leaf role.
CURL_OPTS=(--silent --show-error --fail)
if [[ -n "${VAULT_CACERT:-}" ]]; then
CURL_OPTS+=(--cacert "$VAULT_CACERT")
fi
REQ_BODY="$(jq -n \
--arg csr "$(cat "$WORK/leaf.csr.pem")" \
'{csr: $csr, common_name: "cuecrux daemon C2PA signer", ttl: "1h"}')"
curl "${CURL_OPTS[@]}" \
-H "X-Vault-Token: $VAULT_TOKEN" \
-H "Content-Type: application/json" \
-X POST \
-d "$REQ_BODY" \
"$VAULT_ADDR/v1/$MOUNT/sign/$ROLE" \
| jq -r .data.certificate > "$WORK/leaf.cert.pem"
if [[ ! -s "$WORK/leaf.cert.pem" ]]; then
echo "FATAL: Vault returned empty certificate" >&2
exit 3
fi
# 3. Decode the leaf and assert the strict profile.
TEXT="$(openssl x509 -in "$WORK/leaf.cert.pem" -noout -text)"
# KU = Digital Signature only.
if ! echo "$TEXT" | grep -A1 'X509v3 Key Usage' | grep -E 'Digital Signature$' > /dev/null; then
echo "FAIL: leaf KU is not exactly 'Digital Signature'" >&2
echo "$TEXT" | grep -A1 'X509v3 Key Usage' >&2
exit 4
fi
if echo "$TEXT" | grep -A1 'X509v3 Key Usage' | grep -E 'Certificate Sign|CRL Sign|Key Encipherment|Key Agreement' > /dev/null; then
echo "FAIL: leaf KU includes extra bits beyond Digital Signature" >&2
exit 5
fi
# EKU = E-mail Protection only.
if ! echo "$TEXT" | grep -A1 'X509v3 Extended Key Usage' | grep -E '^[ ]*E-mail Protection$' > /dev/null; then
echo "FAIL: leaf EKU is not exactly 'E-mail Protection'" >&2
echo "$TEXT" | grep -A1 'X509v3 Extended Key Usage' >&2
exit 6
fi
if echo "$TEXT" | grep -A1 'X509v3 Extended Key Usage' | grep -E 'TLS Web|Code Signing|OCSP|Time Stamping' > /dev/null; then
echo "FAIL: leaf EKU includes extra purposes" >&2
exit 7
fi
# BasicConstraints CA:FALSE asserted (NOT absent — the constraint must be present).
if ! echo "$TEXT" | grep -A1 'X509v3 Basic Constraints' | grep -E 'CA:FALSE' > /dev/null; then
echo "FAIL: leaf BasicConstraints is not 'CA:FALSE' (missing or CA:TRUE)" >&2
echo "$TEXT" | grep -A1 'X509v3 Basic Constraints' >&2
exit 8
fi
# Public key algorithm = P-256.
if ! echo "$TEXT" | grep -E 'Public Key Algorithm: id-ecPublicKey' > /dev/null; then
echo "FAIL: leaf is not P-256 / id-ecPublicKey" >&2
exit 9
fi
if ! echo "$TEXT" | grep -E 'ASN1 OID: prime256v1' > /dev/null; then
echo "FAIL: leaf curve is not prime256v1 / secp256r1" >&2
exit 10
fi
# Signature algorithm = ecdsa-with-SHA256.
if ! echo "$TEXT" | grep -E 'Signature Algorithm: ecdsa-with-SHA256' > /dev/null; then
echo "FAIL: leaf signature alg is not ecdsa-with-SHA256" >&2
exit 11
fi
echo "PROFILE OK: leaf has KU=DigitalSignature only, EKU=EmailProtection only,"
echo " BasicConstraints CA:FALSE asserted, P-256 + ecdsa-with-SHA256."