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.
pull/238/head
Anders Åstrand 2 weeks ago committed by AndersAstrand
parent 329bbfba3c
commit d0d0d2dfb4
  1. 175
      contrib/pg_tde/src/access/pg_tde_xlog_keys.c
  2. 90
      contrib/pg_tde/src/access/pg_tde_xlog_smgr.c
  3. 2
      contrib/pg_tde/src/catalog/tde_principal_key.c
  4. 39
      contrib/pg_tde/src/include/access/pg_tde_xlog_keys.h

@ -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));

@ -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);
}
}

@ -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"),

@ -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 */

Loading…
Cancel
Save