Remove cached OpenSSL context from internal keys

Since only WAL encryption use the cached context it should not be part
of every internal key. Instead store it in the WAL decryption key cache
and the backend global state for WAL encryption.
pull/209/head
Andreas Karlsson 6 months ago committed by Andreas Karlsson
parent 1dc74bdfac
commit 27b88e1334
  1. 32
      contrib/pg_tde/src/access/pg_tde_tdemap.c
  2. 9
      contrib/pg_tde/src/access/pg_tde_xlog_encrypt.c
  3. 15
      contrib/pg_tde/src/encryption/enc_tde.c
  4. 3
      contrib/pg_tde/src/include/access/pg_tde_tdemap.h
  5. 10
      contrib/pg_tde/src/include/encryption/enc_tde.h

@ -59,7 +59,7 @@
#define PG_TDE_FILEMAGIC 0x02454454 /* version ID value = TDE 02 */
#define MAP_ENTRY_DAT_SIZE (offsetof(TDEMapEntry, enc_key) + offsetof(InternalKey, ctx))
#define MAP_ENTRY_SIZE sizeof(TDEMapEntry)
#define TDE_FILE_HEADER_SIZE sizeof(TDEFileHeader)
#define MaxXLogRecPtr (~(XLogRecPtr)0)
@ -216,7 +216,6 @@ pg_tde_generate_internal_key(InternalKey *int_key, uint32 entry_type)
{
int_key->rel_type = entry_type;
int_key->start_lsn = InvalidXLogRecPtr;
int_key->ctx = NULL;
if (!RAND_bytes(int_key->key, INTERNAL_KEY_LEN))
ereport(ERROR,
@ -436,10 +435,10 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, InternalKey *
map_entry.enc_key = *enc_rel_key_data;
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
bytes_written = pg_pwrite(fd, &map_entry, MAP_ENTRY_DAT_SIZE, *offset);
bytes_written = pg_pwrite(fd, &map_entry, MAP_ENTRY_SIZE, *offset);
/* Add the entry to the file */
if (bytes_written != MAP_ENTRY_DAT_SIZE)
if (bytes_written != MAP_ENTRY_SIZE)
{
ereport(ERROR,
(errcode_for_file_access(),
@ -778,8 +777,8 @@ pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path)
keyfile_path)));
}
last_key_idx = ((lseek(fd, 0, SEEK_END) - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_DAT_SIZE) - 1;
write_pos = TDE_FILE_HEADER_SIZE + (last_key_idx * MAP_ENTRY_DAT_SIZE) + offsetof(TDEMapEntry, enc_key) + offsetof(InternalKey, start_lsn);
last_key_idx = ((lseek(fd, 0, SEEK_END) - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_SIZE) - 1;
write_pos = TDE_FILE_HEADER_SIZE + (last_key_idx * MAP_ENTRY_SIZE) + offsetof(TDEMapEntry, enc_key) + offsetof(InternalKey, start_lsn);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pwrite(fd, &lsn, sizeof(XLogRecPtr), write_pos) != sizeof(XLogRecPtr))
@ -797,10 +796,10 @@ pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path)
*/
if (last_key_idx > 0)
{
off_t prev_key_pos = TDE_FILE_HEADER_SIZE + ((last_key_idx - 1) * MAP_ENTRY_DAT_SIZE);
off_t prev_key_pos = TDE_FILE_HEADER_SIZE + ((last_key_idx - 1) * MAP_ENTRY_SIZE);
TDEMapEntry prev_map_entry;
if (pg_pread(fd, &prev_map_entry, MAP_ENTRY_DAT_SIZE, prev_key_pos) != MAP_ENTRY_DAT_SIZE)
if (pg_pread(fd, &prev_map_entry, MAP_ENTRY_SIZE, prev_key_pos) != MAP_ENTRY_SIZE)
{
ereport(ERROR,
(errcode_for_file_access(),
@ -811,7 +810,7 @@ pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path)
{
WALKeySetInvalid(&prev_map_entry.enc_key);
if (pg_pwrite(fd, &prev_map_entry, MAP_ENTRY_DAT_SIZE, prev_key_pos) != MAP_ENTRY_DAT_SIZE)
if (pg_pwrite(fd, &prev_map_entry, MAP_ENTRY_SIZE, prev_key_pos) != MAP_ENTRY_SIZE)
{
ereport(ERROR,
(errcode_for_file_access(),
@ -1066,10 +1065,10 @@ pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int fla
/* Read the entry at the given offset */
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
bytes_read = pg_pread(map_file, map_entry, MAP_ENTRY_DAT_SIZE, *offset);
bytes_read = pg_pread(map_file, map_entry, MAP_ENTRY_SIZE, *offset);
/* We've reached the end of the file. */
if (bytes_read != MAP_ENTRY_DAT_SIZE)
if (bytes_read != MAP_ENTRY_SIZE)
return false;
*offset += bytes_read;
@ -1094,10 +1093,10 @@ pg_tde_read_one_map_entry2(int fd, int32 key_index, TDEPrincipalKey *principal_k
off_t read_pos = 0;
/* Calculate the reading position in the file. */
read_pos += (key_index * MAP_ENTRY_DAT_SIZE) + TDE_FILE_HEADER_SIZE;
read_pos += (key_index * MAP_ENTRY_SIZE) + TDE_FILE_HEADER_SIZE;
/* Check if the file has a valid key */
if ((read_pos + MAP_ENTRY_DAT_SIZE) > lseek(fd, 0, SEEK_END))
if ((read_pos + MAP_ENTRY_SIZE) > lseek(fd, 0, SEEK_END))
{
char db_map_path[MAXPGPATH] = {0};
@ -1113,7 +1112,7 @@ pg_tde_read_one_map_entry2(int fd, int32 key_index, TDEPrincipalKey *principal_k
/* Read the encrypted key */
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pread(fd, map_entry, MAP_ENTRY_DAT_SIZE, read_pos) != MAP_ENTRY_DAT_SIZE)
if (pg_pread(fd, map_entry, MAP_ENTRY_SIZE, read_pos) != MAP_ENTRY_SIZE)
{
char db_map_path[MAXPGPATH] = {0};
@ -1288,7 +1287,7 @@ pg_tde_read_last_wal_key(void)
return NULL;
}
file_idx = ((fsize - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_DAT_SIZE) - 1;
file_idx = ((fsize - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_SIZE) - 1;
map_entry = pg_tde_read_one_map_entry2(fd, file_idx, principal_key);
if (!map_entry)
{
@ -1330,7 +1329,7 @@ pg_tde_fetch_wal_keys(XLogRecPtr start_lsn)
fd = pg_tde_open_file(db_map_path, &principal_key->keyInfo, O_RDONLY, &read_pos);
keys_count = (lseek(fd, 0, SEEK_END) - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_DAT_SIZE;
keys_count = (lseek(fd, 0, SEEK_END) - TDE_FILE_HEADER_SIZE) / MAP_ENTRY_SIZE;
/*
* If there is no keys, return a fake one (with the range 0-infinity) so
@ -1399,6 +1398,7 @@ pg_tde_add_wal_key_to_cache(InternalKey *cached_key, XLogRecPtr start_lsn)
wal_rec->start_lsn = start_lsn;
wal_rec->end_lsn = MaxXLogRecPtr;
wal_rec->key = cached_key;
wal_rec->crypt_ctx = NULL;
if (!tde_wal_key_last_rec)
{
tde_wal_key_last_rec = wal_rec;

@ -75,8 +75,8 @@ static InternalKey EncryptionKey =
{
.rel_type = MAP_ENTRY_EMPTY,
.start_lsn = InvalidXLogRecPtr,
.ctx = NULL,
};
static void *EncryptionCryptCtx = NULL;
static int XLOGChooseNumBuffers(void);
@ -176,7 +176,7 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset,
SetXLogPageIVPrefix(tli, segno, iv_prefix);
PG_TDE_ENCRYPT_DATA(iv_prefix, offset,
(char *) buf, count,
enc_buff, key);
enc_buff, key, &EncryptionCryptCtx);
return pg_pwrite(fd, enc_buff, count, offset);
}
@ -195,8 +195,7 @@ TDEXLogSmgrInit(void)
((key->rel_type & TDE_KEY_TYPE_WAL_ENCRYPTED && !EncryptXLog) ||
(key->rel_type & TDE_KEY_TYPE_WAL_UNENCRYPTED && EncryptXLog))))
{
pg_tde_create_wal_key(
&EncryptionKey, &GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID),
pg_tde_create_wal_key(&EncryptionKey, &GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID),
(EncryptXLog ? TDE_KEY_TYPE_WAL_ENCRYPTED : TDE_KEY_TYPE_WAL_UNENCRYPTED));
}
else if (key)
@ -342,7 +341,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset,
PG_TDE_DECRYPT_DATA(iv_prefix, dec_off,
(char *) buf + (offset - dec_off),
dec_sz, (char *) buf + (offset - dec_off),
curr_key->key);
curr_key->key, &curr_key->crypt_ctx);
if (dec_off + dec_sz == offset)
{

@ -37,7 +37,7 @@ iv_prefix_debug(const char *iv_prefix, char *out_hex)
* This function assumes that everything is in a single block, and has an assertion ensuring this
*/
static void
pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, const char *context)
pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, void **ctxPtr, const char *context)
{
const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE;
const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE;
@ -46,7 +46,7 @@ pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data
Assert(aes_end_block - aes_start_block <= NUM_AES_BLOCKS_IN_BATCH + 1);
Aes128EncryptedZeroBlocks(&key->ctx, key->key, iv_prefix, aes_start_block, aes_end_block, enc_key);
Aes128EncryptedZeroBlocks(ctxPtr, key->key, iv_prefix, aes_start_block, aes_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG
{
@ -73,7 +73,7 @@ pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data
* This is a generic function intended for large data, that do not fit into a single block
*/
static void
pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, const char *context)
pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, void **ctxPtr, const char *context)
{
const uint64 aes_start_block = start_offset / AES_BLOCK_SIZE;
const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE;
@ -88,7 +88,7 @@ pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *dat
uint32 current_batch_bytes;
uint64 batch_end_block = Min(batch_start_block + NUM_AES_BLOCKS_IN_BATCH, aes_end_block);
Aes128EncryptedZeroBlocks(&key->ctx, key->key, iv_prefix, batch_start_block, batch_end_block, enc_key);
Aes128EncryptedZeroBlocks(ctxPtr, key->key, iv_prefix, batch_start_block, batch_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG
{
char ivp_debug[33];
@ -141,15 +141,15 @@ pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *dat
* This function simply selects between the two above variations based on the data length
*/
void
pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, const char *context)
pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, void **ctxPtr, const char *context)
{
if (data_len >= DATA_BYTES_PER_AES_BATCH)
{
pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context);
pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, ctxPtr, context);
}
else
{
pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context);
pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, ctxPtr, context);
}
}
@ -200,7 +200,6 @@ AesDecryptKey(const TDEPrincipalKey *principal_key, Oid dbOid, InternalKey **p_r
/* Fill in the structure */
**p_rel_key_data = *enc_rel_key_data;
(*p_rel_key_data)->ctx = NULL;
AesDecrypt(principal_key->keyData, iv, (unsigned char *) enc_rel_key_data, INTERNAL_KEY_LEN, (unsigned char *) *p_rel_key_data, (int *) key_bytes);
}

@ -31,8 +31,6 @@ typedef struct InternalKey
uint32 rel_type;
XLogRecPtr start_lsn;
void *ctx;
} InternalKey;
#define WALKeySetInvalid(key) \
@ -63,6 +61,7 @@ typedef struct WALKeyCacheRec
XLogRecPtr end_lsn;
InternalKey *key;
void *crypt_ctx;
struct WALKeyCacheRec *next;
} WALKeyCacheRec;

@ -12,15 +12,15 @@
#include "access/pg_tde_tdemap.h"
extern void pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, const char *context);
extern void pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, InternalKey *key, void **ctxPtr, const char *context);
/* Function Macros over crypt */
#define PG_TDE_ENCRYPT_DATA(_iv_prefix, _start_offset, _data, _data_len, _out, _key) \
pg_tde_crypt(_iv_prefix, _start_offset, _data, _data_len, _out, _key, "ENCRYPT")
#define PG_TDE_ENCRYPT_DATA(_iv_prefix, _start_offset, _data, _data_len, _out, _key, _ctxptr) \
pg_tde_crypt(_iv_prefix, _start_offset, _data, _data_len, _out, _key, _ctxptr, "ENCRYPT")
#define PG_TDE_DECRYPT_DATA(_iv_prefix, _start_offset, _data, _data_len, _out, _key) \
pg_tde_crypt(_iv_prefix, _start_offset, _data, _data_len, _out, _key, "DECRYPT")
#define PG_TDE_DECRYPT_DATA(_iv_prefix, _start_offset, _data, _data_len, _out, _key, _ctxptr) \
pg_tde_crypt(_iv_prefix, _start_offset, _data, _data_len, _out, _key, _ctxptr, "DECRYPT")
extern void AesEncryptKey(const TDEPrincipalKey *principal_key, Oid dbOid, InternalKey *rel_key_data, InternalKey **p_enc_rel_key_data, size_t *enc_key_bytes);
extern void AesDecryptKey(const TDEPrincipalKey *principal_key, Oid dbOid, InternalKey **p_rel_key_data, InternalKey *enc_rel_key_data, size_t *key_bytes);

Loading…
Cancel
Save