From d0d0d2dfb497e829540389fe1bb7572af4251971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85strand?= Date: Thu, 28 Aug 2025 13:54:49 +0200 Subject: [PATCH] PG-1892 Rework WalEncryptionKey into ranges This structure isn't really a key but meta data for a range of WAL using a given key. Rework these structures to better represent this. Also decouple the structure from the file format and use InternalKey for the actual decrypted key data. There is still plenty of cleanup to do in relation to this, but I believe this is at least easier to understand than what we currently have. I wish the end of the ranges were handled better though, but that is a bit out of scope for this commit. --- contrib/pg_tde/src/access/pg_tde_xlog_keys.c | 175 ++++++++++-------- contrib/pg_tde/src/access/pg_tde_xlog_smgr.c | 90 ++++----- .../pg_tde/src/catalog/tde_principal_key.c | 2 +- .../src/include/access/pg_tde_xlog_keys.h | 39 ++-- 4 files changed, 164 insertions(+), 142 deletions(-) diff --git a/contrib/pg_tde/src/access/pg_tde_xlog_keys.c b/contrib/pg_tde/src/access/pg_tde_xlog_keys.c index 4c14625e008..23a61df4f28 100644 --- a/contrib/pg_tde/src/access/pg_tde_xlog_keys.c +++ b/contrib/pg_tde/src/access/pg_tde_xlog_keys.c @@ -25,19 +25,33 @@ #define PG_TDE_WAL_KEY_FILE_MAGIC 0x014B4557 /* version ID value = WEK 01 */ #define PG_TDE_WAL_KEY_FILE_NAME "wal_keys" -#define MaxXLogRecPtr (~(XLogRecPtr)0) -#define MaxTimeLineID (~(TimeLineID)0) - typedef struct WalKeyFileHeader { int32 file_version; TDESignedPrincipalKeyInfo signed_key_info; } WalKeyFileHeader; +/* + * Feel free to use the unused fields for something, but beware that existing + * files may contain unexpected values here. Also be aware of alignment if + * changing any of the types as this struct is written/read directly from file. + * + * If changes are made, know that the first two fields are used as AAD when + * encrypting/decrypting existing keys from the key files, so any changes here + * might break existing clusters. + */ typedef struct WalKeyFileEntry { - uint32 type; - WalEncryptionKey enc_key; + uint32 _unused1; /* Part of AAD, is 1 or 2 in existing entries */ + uint32 _unused2; /* Part of AAD */ + + uint8 encrypted_key_data[INTERNAL_KEY_LEN]; + uint8 key_base_iv[INTERNAL_KEY_IV_LEN]; + + uint32 range_type; /* WalEncryptionRangeType */ + uint32 _unused3; + WalLocation range_start; + /* IV and tag used when encrypting the key itself */ unsigned char entry_iv[MAP_ENTRY_IV_SIZE]; unsigned char aead_tag[MAP_ENTRY_AEAD_TAG_SIZE]; @@ -46,11 +60,11 @@ typedef struct WalKeyFileEntry static WALKeyCacheRec *tde_wal_key_cache = NULL; static WALKeyCacheRec *tde_wal_prealloc_record = NULL; static WALKeyCacheRec *tde_wal_key_last_rec = NULL; -static WalEncryptionKey *tde_wal_prealloc_key = NULL; +static WalEncryptionRange *tde_wal_prealloc_range = NULL; -static WALKeyCacheRec *pg_tde_add_wal_key_to_cache(WalEncryptionKey *cached_key); -static WalEncryptionKey *pg_tde_decrypt_wal_key(const TDEPrincipalKey *principal_key, WalKeyFileEntry *entry); -static void pg_tde_initialize_wal_key_file_entry(WalKeyFileEntry *entry, const TDEPrincipalKey *principal_key, const WalEncryptionKey *rel_key_data); +static WALKeyCacheRec *pg_tde_add_wal_range_to_cache(WalEncryptionRange *cached_range); +static WalEncryptionRange *pg_tde_wal_range_from_entry(const TDEPrincipalKey *principal_key, WalKeyFileEntry *entry); +static void pg_tde_initialize_wal_key_file_entry(WalKeyFileEntry *entry, const TDEPrincipalKey *principal_key, const WalEncryptionRange *range); static int pg_tde_open_wal_key_file_basic(const char *filename, int flags, bool ignore_missing); static int pg_tde_open_wal_key_file_read(const char *filename, bool ignore_missing, off_t *curr_pos); static int pg_tde_open_wal_key_file_write(const char *filename, const TDESignedPrincipalKeyInfo *signed_key_info, bool truncate, off_t *curr_pos); @@ -59,7 +73,7 @@ static void pg_tde_read_one_wal_key_file_entry2(int fd, int32 key_index, WalKeyF static void pg_tde_wal_key_file_header_read(const char *filename, int fd, WalKeyFileHeader *fheader, off_t *bytes_read); static int pg_tde_wal_key_file_header_write(const char *filename, int fd, const TDESignedPrincipalKeyInfo *signed_key_info, off_t *bytes_written); static void pg_tde_write_one_wal_key_file_entry(int fd, const WalKeyFileEntry *entry, off_t *offset, const char *db_map_path); -static void pg_tde_write_wal_key_file_entry(const WalEncryptionKey *rel_key_data, const TDEPrincipalKey *principal_key); +static void pg_tde_write_wal_key_file_entry(const WalEncryptionRange *range, const TDEPrincipalKey *principal_key); static char * get_wal_key_file_path(void) @@ -90,7 +104,7 @@ pg_tde_free_wal_key_cache(void) } void -pg_tde_wal_last_key_set_location(WalLocation loc) +pg_tde_wal_last_range_set_location(WalLocation loc) { LWLock *lock_pk = tde_lwlock_enc_keys(); int fd; @@ -105,8 +119,7 @@ pg_tde_wal_last_key_set_location(WalLocation loc) last_key_idx = ((lseek(fd, 0, SEEK_END) - sizeof(WalKeyFileHeader)) / sizeof(WalKeyFileEntry)) - 1; write_pos = sizeof(WalKeyFileHeader) + (last_key_idx * sizeof(WalKeyFileEntry)) + - offsetof(WalKeyFileEntry, enc_key) + - offsetof(WalEncryptionKey, wal_start); + offsetof(WalKeyFileEntry, range_start); if (pg_pwrite(fd, &loc, sizeof(WalLocation), write_pos) != sizeof(WalLocation)) { @@ -132,9 +145,9 @@ pg_tde_wal_last_key_set_location(WalLocation loc) errmsg("could not read previous WAL key: %m")); } - if (wal_location_cmp(prev_entry.enc_key.wal_start, loc) >= 0) + if (wal_location_cmp(prev_entry.range_start, loc) >= 0) { - prev_entry.enc_key.type = WAL_KEY_TYPE_INVALID; + prev_entry.range_type = WAL_ENCRYPTION_RANGE_INVALID; if (pg_pwrite(fd, &prev_entry, sizeof(WalKeyFileEntry), prev_key_pos) != sizeof(WalKeyFileEntry)) { @@ -165,7 +178,7 @@ pg_tde_wal_last_key_set_location(WalLocation loc) * with the actual lsn by the first WAL write. */ void -pg_tde_create_wal_key(WalEncryptionKey *rel_key_data, WalEncryptionKeyType entry_type) +pg_tde_create_wal_range(WalEncryptionRange *range, WalEncryptionRangeType type) { TDEPrincipalKey *principal_key; @@ -179,23 +192,16 @@ pg_tde_create_wal_key(WalEncryptionKey *rel_key_data, WalEncryptionKeyType entry errhint("Use pg_tde_set_server_key_using_global_key_provider() to configure one.")); } - /* TODO: no need in generating key if WAL_KEY_TYPE_UNENCRYPTED */ - rel_key_data->type = entry_type; - rel_key_data->wal_start.lsn = InvalidXLogRecPtr; - rel_key_data->wal_start.tli = 0; + /* TODO: no need in generating key if WAL_ENCRYPTION_RANGE_UNENCRYPTED */ + range->type = type; + range->start.lsn = InvalidXLogRecPtr; + range->start.tli = 0; + range->end.lsn = MaxXLogRecPtr; + range->end.tli = MaxTimeLineID; - if (!RAND_bytes(rel_key_data->key, INTERNAL_KEY_LEN)) - ereport(ERROR, - errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not generate WAL encryption key: %s", - ERR_error_string(ERR_get_error(), NULL))); - if (!RAND_bytes(rel_key_data->base_iv, INTERNAL_KEY_IV_LEN)) - ereport(ERROR, - errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not generate IV for WAL encryption key: %s", - ERR_error_string(ERR_get_error(), NULL))); + pg_tde_generate_internal_key(&range->key); - pg_tde_write_wal_key_file_entry(rel_key_data, principal_key); + pg_tde_write_wal_key_file_entry(range, principal_key); #ifdef FRONTEND free(principal_key); @@ -218,8 +224,8 @@ pg_tde_get_wal_cache_keys(void) return tde_wal_key_cache; } -WalEncryptionKey * -pg_tde_read_last_wal_key(void) +WalEncryptionRange * +pg_tde_read_last_wal_range(void) { off_t read_pos = 0; LWLock *lock_pk = tde_lwlock_enc_keys(); @@ -227,7 +233,7 @@ pg_tde_read_last_wal_key(void) int fd; int file_idx; WalKeyFileEntry entry; - WalEncryptionKey *rel_key_data; + WalEncryptionRange *range; off_t fsize; LWLockAcquire(lock_pk, LW_EXCLUSIVE); @@ -255,14 +261,14 @@ pg_tde_read_last_wal_key(void) file_idx = ((fsize - sizeof(WalKeyFileHeader)) / sizeof(WalKeyFileEntry)) - 1; pg_tde_read_one_wal_key_file_entry2(fd, file_idx, &entry); - rel_key_data = pg_tde_decrypt_wal_key(principal_key, &entry); + range = pg_tde_wal_range_from_entry(principal_key, &entry); #ifdef FRONTEND pfree(principal_key); #endif LWLockRelease(lock_pk); CloseTransientFile(fd); - return rel_key_data; + return range; } /* Fetches WAL keys from disk and adds them to the WAL cache */ @@ -297,11 +303,12 @@ pg_tde_fetch_wal_keys(WalLocation start) if (keys_count == 0) { WALKeyCacheRec *wal_rec; - WalEncryptionKey stub_key = { - .wal_start = {.tli = 0,.lsn = InvalidXLogRecPtr}, + WalEncryptionRange stub_range = { + .start = {.tli = 0,.lsn = InvalidXLogRecPtr}, + .end = {.tli = MaxTimeLineID,.lsn = MaxXLogRecPtr}, }; - wal_rec = pg_tde_add_wal_key_to_cache(&stub_key); + wal_rec = pg_tde_add_wal_range_to_cache(&stub_range); #ifdef FRONTEND /* The backend frees it after copying to the cache. */ @@ -321,17 +328,16 @@ pg_tde_fetch_wal_keys(WalLocation start) /* * Skip new (just created but not updated by write) and invalid keys */ - if (wal_location_valid(entry.enc_key.wal_start) && - (entry.enc_key.type == WAL_KEY_TYPE_UNENCRYPTED || - entry.enc_key.type == WAL_KEY_TYPE_ENCRYPTED) && - wal_location_cmp(entry.enc_key.wal_start, start) >= 0) + if (entry.range_type != WAL_ENCRYPTION_RANGE_INVALID && + wal_location_valid(entry.range_start) && + wal_location_cmp(entry.range_start, start) >= 0) { - WalEncryptionKey *rel_key_data = pg_tde_decrypt_wal_key(principal_key, &entry); + WalEncryptionRange *range = pg_tde_wal_range_from_entry(principal_key, &entry); WALKeyCacheRec *wal_rec; - wal_rec = pg_tde_add_wal_key_to_cache(rel_key_data); + wal_rec = pg_tde_add_wal_range_to_cache(range); - pfree(rel_key_data); + pfree(range); if (!return_wal_rec) return_wal_rec = wal_rec; @@ -365,9 +371,9 @@ pg_tde_wal_cache_extra_palloc(void) { tde_wal_prealloc_record = palloc0_object(WALKeyCacheRec); } - if (tde_wal_prealloc_key == NULL) + if (tde_wal_prealloc_range == NULL) { - tde_wal_prealloc_key = palloc0_object(WalEncryptionKey); + tde_wal_prealloc_range = palloc0_object(WalEncryptionRange); } #ifndef FRONTEND MemoryContextSwitchTo(oldCtx); @@ -375,7 +381,7 @@ pg_tde_wal_cache_extra_palloc(void) } static WALKeyCacheRec * -pg_tde_add_wal_key_to_cache(WalEncryptionKey *key) +pg_tde_add_wal_range_to_cache(WalEncryptionRange *range) { WALKeyCacheRec *wal_rec; #ifndef FRONTEND @@ -389,10 +395,7 @@ pg_tde_add_wal_key_to_cache(WalEncryptionKey *key) MemoryContextSwitchTo(oldCtx); #endif - wal_rec->start = key->wal_start; - wal_rec->end.tli = MaxTimeLineID; - wal_rec->end.lsn = MaxXLogRecPtr; - wal_rec->key = *key; + wal_rec->range = *range; wal_rec->crypt_ctx = NULL; if (!tde_wal_key_last_rec) { @@ -402,7 +405,7 @@ pg_tde_add_wal_key_to_cache(WalEncryptionKey *key) else { tde_wal_key_last_rec->next = wal_rec; - tde_wal_key_last_rec->end = wal_rec->start; + tde_wal_key_last_rec->range.end = wal_rec->range.start; tde_wal_key_last_rec = wal_rec; } @@ -574,7 +577,7 @@ pg_tde_read_one_wal_key_file_entry2(int fd, } static void -pg_tde_write_wal_key_file_entry(const WalEncryptionKey *rel_key_data, +pg_tde_write_wal_key_file_entry(const WalEncryptionRange *range, const TDEPrincipalKey *principal_key) { int fd; @@ -591,7 +594,7 @@ pg_tde_write_wal_key_file_entry(const WalEncryptionKey *rel_key_data, curr_pos = lseek(fd, 0, SEEK_END); /* Initialize WAL key file entry and encrypt key */ - pg_tde_initialize_wal_key_file_entry(&write_entry, principal_key, rel_key_data); + pg_tde_initialize_wal_key_file_entry(&write_entry, principal_key, range); /* Write the given entry at curr_pos; i.e. the free entry. */ pg_tde_write_one_wal_key_file_entry(fd, &write_entry, &curr_pos, get_wal_key_file_path()); @@ -599,27 +602,31 @@ pg_tde_write_wal_key_file_entry(const WalEncryptionKey *rel_key_data, CloseTransientFile(fd); } -static WalEncryptionKey * -pg_tde_decrypt_wal_key(const TDEPrincipalKey *principal_key, WalKeyFileEntry *entry) +static WalEncryptionRange * +pg_tde_wal_range_from_entry(const TDEPrincipalKey *principal_key, WalKeyFileEntry *entry) { - WalEncryptionKey *key = tde_wal_prealloc_key == NULL ? palloc_object(WalEncryptionKey) : tde_wal_prealloc_key; + WalEncryptionRange *range = tde_wal_prealloc_range == NULL ? palloc0_object(WalEncryptionRange) : tde_wal_prealloc_range; - tde_wal_prealloc_key = NULL; + tde_wal_prealloc_range = NULL; Assert(principal_key); - *key = entry->enc_key; + range->type = entry->range_type; + range->start = entry->range_start; + range->end.tli = MaxTimeLineID; + range->end.lsn = MaxXLogRecPtr; + memcpy(range->key.base_iv, entry->key_base_iv, INTERNAL_KEY_IV_LEN); if (!AesGcmDecrypt(principal_key->keyData, entry->entry_iv, MAP_ENTRY_IV_SIZE, - (unsigned char *) entry, offsetof(WalKeyFileEntry, enc_key), - entry->enc_key.key, INTERNAL_KEY_LEN, - key->key, + (unsigned char *) entry, offsetof(WalKeyFileEntry, encrypted_key_data), + entry->encrypted_key_data, INTERNAL_KEY_LEN, + range->key.key, entry->aead_tag, MAP_ENTRY_AEAD_TAG_SIZE)) ereport(ERROR, errmsg("Failed to decrypt key, incorrect principal key or corrupted key file")); - return key; + return range; } static void @@ -651,10 +658,22 @@ pg_tde_write_one_wal_key_file_entry(int fd, static void pg_tde_initialize_wal_key_file_entry(WalKeyFileEntry *entry, const TDEPrincipalKey *principal_key, - const WalEncryptionKey *rel_key_data) + const WalEncryptionRange *range) { - entry->type = rel_key_data->type; - entry->enc_key = *rel_key_data; + Assert(range->type == WAL_ENCRYPTION_RANGE_ENCRYPTED || range->type == WAL_ENCRYPTION_RANGE_UNENCRYPTED); + + memset(entry, 0, sizeof(WalKeyFileEntry)); + + /* + * We set this field here so that existing file entries will be consistent + * and future use of this field easier. Some existing entries will have 2 + * here. + */ + entry->_unused1 = 1; + + entry->range_type = range->type; + entry->range_start = range->start; + memcpy(entry->key_base_iv, range->key.base_iv, INTERNAL_KEY_IV_LEN); if (!RAND_bytes(entry->entry_iv, MAP_ENTRY_IV_SIZE)) ereport(ERROR, @@ -663,9 +682,9 @@ pg_tde_initialize_wal_key_file_entry(WalKeyFileEntry *entry, AesGcmEncrypt(principal_key->keyData, entry->entry_iv, MAP_ENTRY_IV_SIZE, - (unsigned char *) entry, offsetof(WalKeyFileEntry, enc_key), - rel_key_data->key, INTERNAL_KEY_LEN, - entry->enc_key.key, + (unsigned char *) entry, offsetof(WalKeyFileEntry, encrypted_key_data), + range->key.key, INTERNAL_KEY_LEN, + entry->encrypted_key_data, entry->aead_tag, MAP_ENTRY_AEAD_TAG_SIZE); } @@ -698,7 +717,7 @@ pg_tde_perform_rotate_server_key(const TDEPrincipalKey *principal_key, /* Read all entries until EOF */ while (1) { - WalEncryptionKey *key; + WalEncryptionRange *range; WalKeyFileEntry read_map_entry; WalKeyFileEntry write_map_entry; @@ -706,12 +725,10 @@ pg_tde_perform_rotate_server_key(const TDEPrincipalKey *principal_key, break; /* Decrypt and re-encrypt key */ - key = pg_tde_decrypt_wal_key(principal_key, &read_map_entry); - pg_tde_initialize_wal_key_file_entry(&write_map_entry, new_principal_key, key); - + range = pg_tde_wal_range_from_entry(principal_key, &read_map_entry); + pg_tde_initialize_wal_key_file_entry(&write_map_entry, new_principal_key, range); pg_tde_write_one_wal_key_file_entry(new_fd, &write_map_entry, &new_curr_pos, tmp_path); - - pfree(key); + pfree(range); } CloseTransientFile(old_fd); @@ -840,7 +857,7 @@ pg_tde_get_server_key_info(void) } int -pg_tde_count_wal_keys_in_file(void) +pg_tde_count_wal_ranges_in_file(void) { File fd; off_t curr_pos = 0; @@ -869,7 +886,7 @@ pg_tde_delete_server_key(void) Oid dbOid = GLOBAL_DATA_TDE_OID; Assert(LWLockHeldByMeInMode(tde_lwlock_enc_keys(), LW_EXCLUSIVE)); - Assert(pg_tde_count_wal_keys_in_file() == 0); + Assert(pg_tde_count_wal_ranges_in_file() == 0); XLogBeginInsert(); XLogRegisterData((char *) &dbOid, sizeof(Oid)); diff --git a/contrib/pg_tde/src/access/pg_tde_xlog_smgr.c b/contrib/pg_tde/src/access/pg_tde_xlog_smgr.c index 79baa95d73a..3a0932675b5 100644 --- a/contrib/pg_tde/src/access/pg_tde_xlog_smgr.c +++ b/contrib/pg_tde/src/access/pg_tde_xlog_smgr.c @@ -41,10 +41,10 @@ static const XLogSmgr tde_xlog_smgr = { static void *EncryptionCryptCtx = NULL; /* TODO: can be swapped out to the disk */ -static WalEncryptionKey EncryptionKey = -{ - .type = WAL_KEY_TYPE_INVALID, - .wal_start = {.tli = 0,.lsn = InvalidXLogRecPtr}, +static WalEncryptionRange CurrentWalEncryptionRange = { + .type = WAL_ENCRYPTION_RANGE_INVALID, + .start = {.tli = 0,.lsn = InvalidXLogRecPtr}, + .end = {.tli = MaxTimeLineID,.lsn = MaxXLogRecPtr}, }; /* @@ -223,7 +223,7 @@ TDEXLogSmgrInit() void TDEXLogSmgrInitWrite(bool encrypt_xlog) { - WalEncryptionKey *key; + WalEncryptionRange *range; WALKeyCacheRec *keys; /* @@ -233,7 +233,7 @@ TDEXLogSmgrInitWrite(bool encrypt_xlog) */ pg_tde_free_wal_key_cache(); - key = pg_tde_read_last_wal_key(); + range = pg_tde_read_last_wal_range(); /* * Always generate a new key on starting PostgreSQL to protect against @@ -242,16 +242,16 @@ TDEXLogSmgrInitWrite(bool encrypt_xlog) */ if (encrypt_xlog) { - pg_tde_create_wal_key(&EncryptionKey, WAL_KEY_TYPE_ENCRYPTED); + pg_tde_create_wal_range(&CurrentWalEncryptionRange, WAL_ENCRYPTION_RANGE_ENCRYPTED); } - else if (key && key->type == WAL_KEY_TYPE_ENCRYPTED) + else if (range && range->type == WAL_ENCRYPTION_RANGE_ENCRYPTED) { - pg_tde_create_wal_key(&EncryptionKey, WAL_KEY_TYPE_UNENCRYPTED); + pg_tde_create_wal_range(&CurrentWalEncryptionRange, WAL_ENCRYPTION_RANGE_UNENCRYPTED); } - else if (key) + else if (range) { - EncryptionKey = *key; - TDEXLogSetEncKeyLocation(EncryptionKey.wal_start); + CurrentWalEncryptionRange = *range; + TDEXLogSetEncKeyLocation(CurrentWalEncryptionRange.start); } keys = pg_tde_get_wal_cache_keys(); @@ -265,8 +265,8 @@ TDEXLogSmgrInitWrite(bool encrypt_xlog) pg_tde_wal_cache_extra_palloc(); } - if (key) - pfree(key); + if (range) + pfree(range); } /* @@ -280,13 +280,14 @@ void TDEXLogSmgrInitWriteOldKeys() { WALKeyCacheRec *keys; - WalEncryptionKey dummy = { - .type = WAL_KEY_TYPE_UNENCRYPTED, - .wal_start = {.tli = -1,.lsn = -1} + WalEncryptionRange dummy = { + .type = WAL_ENCRYPTION_RANGE_UNENCRYPTED, + .start = {.tli = MaxTimeLineID,.lsn = MaxXLogRecPtr}, + .end = {.tli = MaxTimeLineID,.lsn = MaxXLogRecPtr}, }; - EncryptionKey = dummy; - TDEXLogSetEncKeyLocation(dummy.wal_start); + CurrentWalEncryptionRange = dummy; + TDEXLogSetEncKeyLocation(dummy.start); keys = pg_tde_get_wal_cache_keys(); @@ -333,7 +334,7 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset, TimeLineID tli, XLogSegNo segno) { char iv_prefix[16]; - WalEncryptionKey *key = &EncryptionKey; + WalEncryptionRange *range = &CurrentWalEncryptionRange; char *enc_buff = EncryptionBuf; #ifndef FRONTEND @@ -342,17 +343,17 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset, #ifdef TDE_XLOG_DEBUG elog(DEBUG1, "write encrypted WAL, size: %lu, offset: %ld [%lX], seg: %X/%X, key_start_lsn: %u_%X/%X", - count, offset, offset, LSN_FORMAT_ARGS(segno), key->wal_start.tli, LSN_FORMAT_ARGS(key->wal_start.lsn)); + count, offset, offset, LSN_FORMAT_ARGS(segno), range->start.tli, LSN_FORMAT_ARGS(range->start.lsn)); #endif - CalcXLogPageIVPrefix(tli, segno, key->base_iv, iv_prefix); + CalcXLogPageIVPrefix(tli, segno, range->key.base_iv, iv_prefix); pg_tde_stream_crypt(iv_prefix, offset, (char *) buf, count, enc_buff, - key->key, + range->key.key, &EncryptionCryptCtx); return pg_pwrite(fd, enc_buff, count, offset); @@ -384,15 +385,15 @@ tde_ensure_xlog_key_location(WalLocation loc) lastKeyUsable = (writeKeyLoc.lsn != 0); afterWriteKey = wal_location_cmp(writeKeyLoc, loc) <= 0; - if (EncryptionKey.type != WAL_KEY_TYPE_INVALID && !lastKeyUsable && afterWriteKey && !crashRecovery) + if (CurrentWalEncryptionRange.type != WAL_ENCRYPTION_RANGE_INVALID && !lastKeyUsable && afterWriteKey && !crashRecovery) { WALKeyCacheRec *last_key = pg_tde_get_last_wal_key(); - if (last_key == NULL || last_key->start.lsn < loc.lsn) + if (last_key == NULL || last_key->range.start.lsn < loc.lsn) { - pg_tde_wal_last_key_set_location(loc); - EncryptionKey.wal_start = loc; - TDEXLogSetEncKeyLocation(EncryptionKey.wal_start); + pg_tde_wal_last_range_set_location(loc); + CurrentWalEncryptionRange.start = loc; + TDEXLogSetEncKeyLocation(CurrentWalEncryptionRange.start); lastKeyUsable = true; } } @@ -410,11 +411,11 @@ tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset, XLogSegNoOffsetToRecPtr(segno, offset, segSize, loc.lsn); lastKeyUsable = tde_ensure_xlog_key_location(loc); - if (!lastKeyUsable && EncryptionKey.type != WAL_KEY_TYPE_INVALID) + if (!lastKeyUsable && CurrentWalEncryptionRange.type != WAL_ENCRYPTION_RANGE_INVALID) { return TDEXLogWriteEncryptedPagesOldKeys(fd, buf, count, offset, tli, segno, segSize); } - else if (EncryptionKey.type == WAL_KEY_TYPE_ENCRYPTED) + else if (CurrentWalEncryptionRange.type == WAL_ENCRYPTION_RANGE_ENCRYPTED) { return TDEXLogWriteEncryptedPages(fd, buf, count, offset, tli, segno); } @@ -481,7 +482,7 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, WalLocation write_loc = {.tli = TDEXLogGetEncKeyTli(),.lsn = write_key_lsn}; /* write has generated a new key, need to fetch it */ - if (last_key != NULL && wal_location_cmp(last_key->start, write_loc) < 0) + if (last_key != NULL && wal_location_cmp(last_key->range.start, write_loc) < 0) { pg_tde_fetch_wal_keys(write_loc); @@ -501,19 +502,20 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, { #ifdef TDE_XLOG_DEBUG elog(DEBUG1, "WAL key %u_%X/%X - %u_%X/%X, encrypted: %s", - curr_key->start.tli, LSN_FORMAT_ARGS(curr_key->start.lsn), - curr_key->end.tli, LSN_FORMAT_ARGS(curr_key->end.lsn), - curr_key->key.type == WAL_KEY_TYPE_ENCRYPTED ? "yes" : "no"); + curr_key->range.start.tli, LSN_FORMAT_ARGS(curr_key->range.start.lsn), + curr_key->range.end.tli, LSN_FORMAT_ARGS(curr_key->range.end.lsn), + curr_key->range.type == WAL_ENCRYPTION_RANGE_ENCRYPTED ? "yes" : "no"); #endif - if (wal_location_valid(curr_key->key.wal_start) && - curr_key->key.type == WAL_KEY_TYPE_ENCRYPTED) + if (wal_location_valid(curr_key->range.start) && + curr_key->range.type == WAL_ENCRYPTION_RANGE_ENCRYPTED) { /* * Check if the key's range overlaps with the buffer's and decypt * the part that does. */ - if (wal_location_cmp(data_start, curr_key->end) < 0 && wal_location_cmp(data_end, curr_key->start) > 0) + if (wal_location_cmp(data_start, curr_key->range.end) < 0 && + wal_location_cmp(data_end, curr_key->range.start) > 0) { char iv_prefix[16]; @@ -544,11 +546,11 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, size_t end_lsn = - data_end.tli < curr_key->end.tli ? data_end.lsn : - Min(data_end.lsn, curr_key->end.lsn); + data_end.tli < curr_key->range.end.tli ? data_end.lsn : + Min(data_end.lsn, curr_key->range.end.lsn); size_t start_lsn = - data_start.tli > curr_key->start.tli ? data_start.lsn : - Max(data_start.lsn, curr_key->start.lsn); + data_start.tli > curr_key->range.start.tli ? data_start.lsn : + Max(data_start.lsn, curr_key->range.start.lsn); off_t dec_off = XLogSegmentOffset(start_lsn, segSize); off_t dec_end = @@ -559,7 +561,7 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, Assert(dec_off >= offset); - CalcXLogPageIVPrefix(tli, segno, curr_key->key.base_iv, + CalcXLogPageIVPrefix(tli, segno, curr_key->range.key.base_iv, iv_prefix); /* @@ -575,7 +577,7 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, #ifdef TDE_XLOG_DEBUG elog(DEBUG1, "decrypt WAL, dec_off: %lu [buff_off %lu], sz: %lu | key %u_%X/%X", - dec_off, dec_off - offset, dec_sz, curr_key->key.wal_start.tli, LSN_FORMAT_ARGS(curr_key->key.wal_start.lsn)); + dec_off, dec_off - offset, dec_sz, curr_key->range.start.tli, LSN_FORMAT_ARGS(curr_key->range.start.lsn)); #endif pg_tde_stream_crypt(iv_prefix, @@ -583,7 +585,7 @@ TDEXLogCryptBuffer(const void *buf, void *out_buf, size_t count, off_t offset, dec_buf, dec_sz, o_buf, - curr_key->key.key, + curr_key->range.key.key, &curr_key->crypt_ctx); } } diff --git a/contrib/pg_tde/src/catalog/tde_principal_key.c b/contrib/pg_tde/src/catalog/tde_principal_key.c index abb160f47e2..7c2ef542b80 100644 --- a/contrib/pg_tde/src/catalog/tde_principal_key.c +++ b/contrib/pg_tde/src/catalog/tde_principal_key.c @@ -812,7 +812,7 @@ pg_tde_delete_default_key(PG_FUNCTION_ARGS) principal_key = GetPrincipalKeyNoDefault(GLOBAL_DATA_TDE_OID, LW_EXCLUSIVE); if (pg_tde_is_same_principal_key(default_principal_key, principal_key)) { - if (pg_tde_count_wal_keys_in_file() != 0) + if (pg_tde_count_wal_ranges_in_file() != 0) ereport(ERROR, errcode(ERRCODE_OBJECT_IN_USE), errmsg("cannot delete default principal key"), diff --git a/contrib/pg_tde/src/include/access/pg_tde_xlog_keys.h b/contrib/pg_tde/src/include/access/pg_tde_xlog_keys.h index 63c2e202151..047d76414e9 100644 --- a/contrib/pg_tde/src/include/access/pg_tde_xlog_keys.h +++ b/contrib/pg_tde/src/include/access/pg_tde_xlog_keys.h @@ -5,13 +5,14 @@ #include "access/pg_tde_keys_common.h" #include "access/pg_tde_tdemap.h" +#include "encryption/enc_tde.h" typedef enum { - WAL_KEY_TYPE_INVALID = 0, - WAL_KEY_TYPE_UNENCRYPTED = 1, - WAL_KEY_TYPE_ENCRYPTED = 2, -} WalEncryptionKeyType; + WAL_ENCRYPTION_RANGE_INVALID = 0, + WAL_ENCRYPTION_RANGE_UNENCRYPTED = 1, + WAL_ENCRYPTION_RANGE_ENCRYPTED = 2, +} WalEncryptionRangeType; typedef struct WalLocation { @@ -47,14 +48,19 @@ wal_location_valid(WalLocation loc) return loc.tli != 0 && loc.lsn != InvalidXLogRecPtr; } -typedef struct WalEncryptionKey +#define MaxXLogRecPtr UINT64_MAX +#define MaxTimeLineID UINT32_MAX + +typedef struct WalEncryptionRange { - uint8 key[INTERNAL_KEY_LEN]; - uint8 base_iv[INTERNAL_KEY_IV_LEN]; - uint32 type; + WalEncryptionRangeType type; + + /* key is only used when type is WAL_ENCRYPTION_RANGE_ENCRYPTED */ + InternalKey key; - WalLocation wal_start; -} WalEncryptionKey; + WalLocation start; + WalLocation end; +} WalEncryptionRange; /* * TODO: For now it's a simple linked list which is no good. So consider having @@ -62,17 +68,14 @@ typedef struct WalEncryptionKey */ typedef struct WALKeyCacheRec { - WalLocation start; - WalLocation end; - - WalEncryptionKey key; + WalEncryptionRange range; void *crypt_ctx; struct WALKeyCacheRec *next; } WALKeyCacheRec; -extern int pg_tde_count_wal_keys_in_file(void); -extern void pg_tde_create_wal_key(WalEncryptionKey *rel_key_data, WalEncryptionKeyType entry_type); +extern int pg_tde_count_wal_ranges_in_file(void); +extern void pg_tde_create_wal_range(WalEncryptionRange *range, WalEncryptionRangeType type); extern void pg_tde_delete_server_key(void); extern WALKeyCacheRec *pg_tde_fetch_wal_keys(WalLocation start); extern void pg_tde_free_wal_key_cache(void); @@ -80,10 +83,10 @@ extern WALKeyCacheRec *pg_tde_get_last_wal_key(void); extern TDESignedPrincipalKeyInfo *pg_tde_get_server_key_info(void); extern WALKeyCacheRec *pg_tde_get_wal_cache_keys(void); extern void pg_tde_perform_rotate_server_key(const TDEPrincipalKey *principal_key, const TDEPrincipalKey *new_principal_key, bool write_xlog); -extern WalEncryptionKey *pg_tde_read_last_wal_key(void); +extern WalEncryptionRange *pg_tde_read_last_wal_range(void); extern void pg_tde_save_server_key(const TDEPrincipalKey *principal_key, bool write_xlog); extern void pg_tde_save_server_key_redo(const TDESignedPrincipalKeyInfo *signed_key_info); -extern void pg_tde_wal_last_key_set_location(WalLocation loc); +extern void pg_tde_wal_last_range_set_location(WalLocation loc); extern void pg_tde_wal_cache_extra_palloc(void); #endif /* PG_TDE_XLOG_KEYS_H */