security: authenticate key_base_iv in the WAL key file (M2, WAL keys)#19
Merged
Conversation
key_base_iv is the base IV for WAL data (AES-CTR). In the version-2 WAL key file format it was stored after the AEAD tag, outside the additional authenticated data, so the AAD covered only cipher and range_type. An actor with write access to the WAL key file could alter key_base_iv undetected and shift the WAL IV, which for a stream cipher is a confidentiality break. Move key_base_iv ahead of range_start in WalKeyFileEntry so the AAD (offsetof(range_start)) now authenticates it, and bump the WAL key file version 2 -> 3. range_start stays outside the AAD because it is zero at key creation and updated in place by the first WAL write. The version bump keeps read compatibility: open_pg_tde_update_wal_keys_file migrates an older file at startup. A new v2 dual-read reader (WalKeyFileEntryV2 + range_from_disk_entry_v2) decrypts a version-2 entry with the old AAD and re-wraps it as version 3, alongside the existing v1 reader. This mirrors the key map file fix (#15) for the WAL key file. - t/wal_key_base_iv_migration.pl: a version-2 data directory fixture (WAL encryption enabled) migrates to version 3 on startup and the WAL key still decrypts; data written under v2 stays readable. - t/wal_key_auth.pl: tampering key_base_iv in a v3 entry now fails the WAL key decryption, so the server refuses to start. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M2 (WAL keys): key_base_iv unauthenticated in the WAL key file
Companion to #15, which authenticated
key_base_ivin the relation key map file. This does the same for the WAL key file.Problem
key_base_ivis the base IV for WAL data (AES-CTR). In the version-2 WAL key file format it was stored after the AEAD tag, outside the additional authenticated data, so the AAD (offsetof(WalKeyFileEntry, range_start)) covered onlycipherandrange_type. An actor with write access to the WAL key file could alterkey_base_ivundetected and shift the WAL IV, which for a stream cipher is a confidentiality break.Fix
key_base_ivahead ofrange_startinWalKeyFileEntryso the AAD now authenticates it. The AAD expression is unchanged (offsetof(range_start)); it simply covers more now.range_startstays outside the AAD because it is zero at key creation and updated in place by the first WAL write.2 -> 3(0x024B4557 -> 0x034B4557).Migration (read compatibility preserved)
open_pg_tde_update_wal_keys_filealready migrates an older file at startup. A new v2 dual-read reader (WalKeyFileEntryV2+range_from_disk_entry_v2) decrypts a version-2 entry with the old AAD and re-wraps it as version 3, alongside the existing v1 reader. Migration re-wraps the same key bytes, so existing WAL stays decryptable.Tests
t/wal_key_base_iv_migration.pl— a version-2 data directory fixture (WAL encryption enabled) migrates to version 3 on startup; the WAL key still decrypts,wal_keysis version 3 afterward, data written under v2 is readable, and new WAL can be written. PG18-only (fixture built on 18), mirroring security: authenticate key_base_iv in the key map file (M2, relation keys) #15.t/wal_key_auth.pl— on a v3 cluster, flipping one byte ofkey_base_ivin the last WAL key entry makes the WAL key fail to decrypt, so the server refuses to start withFailed to decrypt key.Validation
meson testsuite green (56/56, including both new tests); the migration test exercises the v2 reader end to end.key_base_ivfrom the AAD makes the tamper test's detection assertion fail (the server then only fails on unrelated WAL corruption, not authentication), confirming the test targets the fix.pgindent/perltidyclean.🤖 Generated with Claude Code