mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 12:41:30 +00:00
90210c9334
Pre-login rows previously persisted the OIDC state, nonce, and PKCE
verifier as plaintext columns; an operator restoring an unredacted
backup of oidc_pre_login_sessions to a debug environment leaked every
in-flight handshake. If the IdP also leaked the auth code in the same
window (logged at a misconfigured TLS terminator, etc.), the attacker
could exchange code + verifier directly. RFC 7636 §7 requires verifier
confidentiality.
This commit:
- Migration 000041 adds {state,nonce,pkce_verifier}_enc BYTEA columns
and makes the legacy plaintext columns nullable. A follow-up
migration drops the plaintext columns once the rolling deploy
completes.
- internal/repository/postgres/oidc_prelogin.go::Create encrypts the
three secrets via crypto.EncryptIfKeySet (v3 magic 0x03 + per-row
salt + nonce + AES-256-GCM tag) and writes only the encrypted
columns; legacy plaintext stays NULL on the write path.
- LookupAndConsume prefers encrypted columns via materialize(),
falling back to the legacy plaintext only when _enc is NULL — the
rolling-deploy compat layer that 000042 will retire.
- NewPreLoginRepository takes encryptionKey; cmd/server/main.go threads
cfg.Encryption.ConfigEncryptionKey in.
- Encryption key reuses CERTCTL_CONFIG_ENCRYPTION_KEY (same passphrase
already protecting OIDC client secrets and SessionSigningKey material).
No new env var.
Why encryption-at-rest, not HMAC: the spec's HMAC approach required
moving plaintext into the cookie (the cookie currently carries only
row ID + HMAC). Re-shaping the cookie wire format would be a larger
refactor; the audit explicitly admits encryption-at-rest is an
acceptable closure (weaker because backups still contain decryptable
ciphertext, but the encryption key is held separately from the DB
backup, and the 10-minute TTL further bounds usable secret window).
Three new regression tests in oidc_prelogin_encryption_test.go pin:
(a) _enc columns contain v3-format ciphertext, NOT plaintext
substrings, post-Create
(b) legacy plaintext columns are NULL post-Create (defends against
future patches that re-introduce plaintext writes)
(c) LookupAndConsume round-trips state/nonce/verifier byte-for-byte
A fourth test pins the legacy-row fallback for rolling-deploy compat.
Refs: cowork/auth-bundles-audit-2026-05-10.md HIGH-5
Spec: cowork/auth-bundles-fixes-2026-05-10/09-high-5-prelogin-secret-protection.md
22 lines
973 B
SQL
22 lines
973 B
SQL
-- =============================================================================
|
|
-- Rollback for 000041_prelogin_encrypted.up.sql.
|
|
--
|
|
-- Drops the {state,nonce,pkce_verifier}_enc columns and re-adds the NOT NULL
|
|
-- constraint on the plaintext columns. Safe because no in-flight rows persist
|
|
-- past the 10-minute TTL — the GC sweep removes legacy rows quickly.
|
|
-- =============================================================================
|
|
|
|
ALTER TABLE oidc_pre_login_sessions
|
|
DROP COLUMN IF EXISTS state_enc,
|
|
DROP COLUMN IF EXISTS nonce_enc,
|
|
DROP COLUMN IF EXISTS pkce_verifier_enc;
|
|
|
|
-- Re-applying NOT NULL would fail if there are any rows missing the plaintext;
|
|
-- truncate the table to remove any stragglers (only handshake-state, safe).
|
|
TRUNCATE TABLE oidc_pre_login_sessions;
|
|
|
|
ALTER TABLE oidc_pre_login_sessions
|
|
ALTER COLUMN state SET NOT NULL,
|
|
ALTER COLUMN nonce SET NOT NULL,
|
|
ALTER COLUMN pkce_verifier SET NOT NULL;
|