PG-1416 Sign principal key info to protect against the wrong principal key

We already had protection against decrypting relation keys with the wrong
principal key but to properly protect us against new relation keys being
encrypted with the wrong principal key we need to also verify that the
principal key was correct when we fetch the principal key from the key
provider. We do so by signing the principal key info header of the key map
file using AES-128-GCM.

This way we cannot get a jumbled mess of relation keys encrypted with
multiple different principal keys.
This commit is contained in:
Andreas Karlsson 2025-04-04 19:41:38 +02:00 committed by Andreas Karlsson
parent e9d4927b2c
commit 5514727353
6 changed files with 103 additions and 55 deletions

View File

@ -66,7 +66,7 @@
typedef struct TDEFileHeader typedef struct TDEFileHeader
{ {
int32 file_version; int32 file_version;
TDEPrincipalKeyInfo principal_key_info; TDESignedPrincipalKeyInfo signed_key_info;
} TDEFileHeader; } TDEFileHeader;
typedef struct RelKeyCacheRec typedef struct RelKeyCacheRec
@ -125,13 +125,14 @@ static InternalKey *pg_tde_put_key_into_cache(const RelFileLocator *locator, Int
static InternalKey *pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type); static InternalKey *pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type);
static InternalKey *pg_tde_create_local_key(const RelFileLocator *newrlocator, uint32 entry_type); static InternalKey *pg_tde_create_local_key(const RelFileLocator *newrlocator, uint32 entry_type);
static void pg_tde_generate_internal_key(InternalKey *int_key, uint32 entry_type); static void pg_tde_generate_internal_key(InternalKey *int_key, uint32 entry_type);
static int pg_tde_file_header_write(const char *tde_filename, int fd, TDEPrincipalKeyInfo *principal_key_info, off_t *bytes_written); static int pg_tde_file_header_write(const char *tde_filename, int fd, const TDESignedPrincipalKeyInfo *signed_key_info, off_t *bytes_written);
static void pg_tde_sign_principal_key_info(TDESignedPrincipalKeyInfo *signed_key_info, const TDEPrincipalKey *principal_key);
static off_t pg_tde_write_one_map_entry(int fd, const TDEMapEntry *map_entry, off_t *offset, const char *db_map_path); static off_t pg_tde_write_one_map_entry(int fd, const TDEMapEntry *map_entry, off_t *offset, const char *db_map_path);
static void pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_data, TDEPrincipalKey *principal_key, bool write_xlog); static void pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_data, TDEPrincipalKey *principal_key, bool write_xlog);
static bool pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t offset); static bool pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t offset);
static int keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, off_t *curr_pos); static int keyrotation_init_file(const TDESignedPrincipalKeyInfo *signed_key_info, char *rotated_filename, const char *filename, off_t *curr_pos);
static void finalize_key_rotation(const char *path_old, const char *path_new); static void finalize_key_rotation(const char *path_old, const char *path_new);
static int pg_tde_open_file_write(const char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool truncate, off_t *curr_pos); static int pg_tde_open_file_write(const char *tde_filename, const TDESignedPrincipalKeyInfo *signed_key_info, bool truncate, off_t *curr_pos);
static void update_wal_keys_cache(void); static void update_wal_keys_cache(void);
InternalKey * InternalKey *
@ -264,11 +265,18 @@ pg_tde_delete_tde_files(Oid dbOid)
} }
void void
pg_tde_save_principal_key_redo(TDEPrincipalKeyInfo *principal_key_info) pg_tde_save_principal_key_redo(const TDESignedPrincipalKeyInfo *signed_key_info)
{ {
int map_fd;
off_t curr_pos;
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_path(signed_key_info->data.databaseId, db_map_path);
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE); LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
pg_tde_save_principal_key(principal_key_info); map_fd = pg_tde_open_file_write(db_map_path, signed_key_info, true, &curr_pos);
close(map_fd);
LWLockRelease(tde_lwlock_enc_keys()); LWLockRelease(tde_lwlock_enc_keys());
} }
@ -282,18 +290,21 @@ pg_tde_save_principal_key_redo(TDEPrincipalKeyInfo *principal_key_info)
* The caller must have an EXCLUSIVE LOCK on the files before calling this function. * The caller must have an EXCLUSIVE LOCK on the files before calling this function.
*/ */
void void
pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info) pg_tde_save_principal_key(const TDEPrincipalKey *principal_key)
{ {
int map_fd = -1; int map_fd = -1;
off_t curr_pos = 0; off_t curr_pos = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
TDESignedPrincipalKeyInfo signed_key_Info;
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_path(principal_key_info->databaseId, db_map_path); pg_tde_set_db_file_path(principal_key->keyInfo.databaseId, db_map_path);
ereport(DEBUG2, (errmsg("pg_tde_save_principal_key"))); ereport(DEBUG2, (errmsg("pg_tde_save_principal_key")));
map_fd = pg_tde_open_file_write(db_map_path, principal_key_info, true, &curr_pos); pg_tde_sign_principal_key_info(&signed_key_Info, principal_key);
map_fd = pg_tde_open_file_write(db_map_path, &signed_key_Info, true, &curr_pos);
close(map_fd); close(map_fd);
} }
@ -301,17 +312,17 @@ pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info)
* Write TDE file header to a TDE file. * Write TDE file header to a TDE file.
*/ */
static int static int
pg_tde_file_header_write(const char *tde_filename, int fd, TDEPrincipalKeyInfo *principal_key_info, off_t *bytes_written) pg_tde_file_header_write(const char *tde_filename, int fd, const TDESignedPrincipalKeyInfo *signed_key_info, off_t *bytes_written)
{ {
TDEFileHeader fheader; TDEFileHeader fheader;
Assert(principal_key_info); Assert(signed_key_info);
/* Create the header for this file. */ /* Create the header for this file. */
fheader.file_version = PG_TDE_FILEMAGIC; fheader.file_version = PG_TDE_FILEMAGIC;
/* Fill in the data */ /* Fill in the data */
fheader.principal_key_info = *principal_key_info; fheader.signed_key_info = *signed_key_info;
*bytes_written = pg_pwrite(fd, &fheader, TDE_FILE_HEADER_SIZE, 0); *bytes_written = pg_pwrite(fd, &fheader, TDE_FILE_HEADER_SIZE, 0);
@ -335,6 +346,19 @@ pg_tde_file_header_write(const char *tde_filename, int fd, TDEPrincipalKeyInfo *
return fd; return fd;
} }
static void
pg_tde_sign_principal_key_info(TDESignedPrincipalKeyInfo *signed_key_info, const TDEPrincipalKey *principal_key)
{
signed_key_info->data = principal_key->keyInfo;
if (!RAND_bytes(signed_key_info->sign_iv, MAP_ENTRY_EMPTY_IV_SIZE))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate iv for key map: %s", ERR_error_string(ERR_get_error(), NULL))));
AesGcmEncrypt(principal_key->keyData, signed_key_info->sign_iv, (unsigned char *) &signed_key_info->data, sizeof(signed_key_info->data), NULL, 0, NULL, signed_key_info->aead_tag);
}
static void static void
pg_tde_initialize_map_entry(TDEMapEntry *map_entry, const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, const InternalKey *rel_key_data) pg_tde_initialize_map_entry(TDEMapEntry *map_entry, const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, const InternalKey *rel_key_data)
{ {
@ -399,14 +423,17 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_
off_t curr_pos = 0; off_t curr_pos = 0;
off_t prev_pos = 0; off_t prev_pos = 0;
TDEMapEntry write_map_entry; TDEMapEntry write_map_entry;
TDESignedPrincipalKeyInfo signed_key_Info;
Assert(rlocator); Assert(rlocator);
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_path(rlocator->dbOid, db_map_path); pg_tde_set_db_file_path(rlocator->dbOid, db_map_path);
pg_tde_sign_principal_key_info(&signed_key_Info, principal_key);
/* Open and validate file for basic correctness. */ /* Open and validate file for basic correctness. */
map_fd = pg_tde_open_file_write(db_map_path, &principal_key->keyInfo, false, &curr_pos); map_fd = pg_tde_open_file_write(db_map_path, &signed_key_Info, false, &curr_pos);
prev_pos = curr_pos; prev_pos = curr_pos;
/* /*
@ -438,7 +465,7 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_
XLogRelKey xlrec; XLogRelKey xlrec;
xlrec.mapEntry = write_map_entry; xlrec.mapEntry = write_map_entry;
xlrec.pkInfo = principal_key->keyInfo; xlrec.pkInfo = signed_key_Info;
XLogBeginInsert(); XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(xlrec)); XLogRegisterData((char *) &xlrec, sizeof(xlrec));
@ -466,7 +493,7 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_
* concurrent in place updates leading to data conflicts. * concurrent in place updates leading to data conflicts.
*/ */
void void
pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDEPrincipalKeyInfo *principal_key_info) pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDESignedPrincipalKeyInfo *signed_key_info)
{ {
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
int map_fd = -1; int map_fd = -1;
@ -474,12 +501,12 @@ pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDEPrincipal
off_t prev_pos = 0; off_t prev_pos = 0;
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_path(principal_key_info->databaseId, db_map_path); pg_tde_set_db_file_path(signed_key_info->data.databaseId, db_map_path);
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE); LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
/* Open and validate file for basic correctness. */ /* Open and validate file for basic correctness. */
map_fd = pg_tde_open_file_write(db_map_path, principal_key_info, false, &curr_pos); map_fd = pg_tde_open_file_write(db_map_path, signed_key_info, false, &curr_pos);
prev_pos = curr_pos; prev_pos = curr_pos;
/* /*
@ -631,7 +658,7 @@ pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset)
* No error checking by this function. * No error checking by this function.
*/ */
static File static File
keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, off_t *curr_pos) keyrotation_init_file(const TDESignedPrincipalKeyInfo *signed_key_info, char *rotated_filename, const char *filename, off_t *curr_pos)
{ {
/* /*
* Set the new filenames for the key rotation process - temporary at the * Set the new filenames for the key rotation process - temporary at the
@ -640,7 +667,7 @@ keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated
snprintf(rotated_filename, MAXPGPATH, "%s.r", filename); snprintf(rotated_filename, MAXPGPATH, "%s.r", filename);
/* Create file, truncate if the rotate file already exits */ /* Create file, truncate if the rotate file already exits */
return pg_tde_open_file_write(rotated_filename, new_principal_key_info, true, curr_pos); return pg_tde_open_file_write(rotated_filename, signed_key_info, true, curr_pos);
} }
/* /*
@ -666,14 +693,17 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0}; off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0};
int fd[PRINCIPAL_KEY_COUNT]; int fd[PRINCIPAL_KEY_COUNT];
char path[PRINCIPAL_KEY_COUNT][MAXPGPATH]; char path[PRINCIPAL_KEY_COUNT][MAXPGPATH];
TDESignedPrincipalKeyInfo new_signed_key_info;
off_t map_size; off_t map_size;
XLogPrincipalKeyRotate *xlrec; XLogPrincipalKeyRotate *xlrec;
off_t xlrec_size; off_t xlrec_size;
pg_tde_set_db_file_path(principal_key->keyInfo.databaseId, path[OLD_PRINCIPAL_KEY]); pg_tde_set_db_file_path(principal_key->keyInfo.databaseId, path[OLD_PRINCIPAL_KEY]);
pg_tde_sign_principal_key_info(&new_signed_key_info, new_principal_key);
fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file_read(path[OLD_PRINCIPAL_KEY], &curr_pos[OLD_PRINCIPAL_KEY]); fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file_read(path[OLD_PRINCIPAL_KEY], &curr_pos[OLD_PRINCIPAL_KEY]);
fd[NEW_PRINCIPAL_KEY] = keyrotation_init_file(&new_principal_key->keyInfo, path[NEW_PRINCIPAL_KEY], path[OLD_PRINCIPAL_KEY], &curr_pos[NEW_PRINCIPAL_KEY]); fd[NEW_PRINCIPAL_KEY] = keyrotation_init_file(&new_signed_key_info, path[NEW_PRINCIPAL_KEY], path[OLD_PRINCIPAL_KEY], &curr_pos[NEW_PRINCIPAL_KEY]);
/* Read all entries until EOF */ /* Read all entries until EOF */
while (1) while (1)
@ -763,10 +793,10 @@ pg_tde_write_map_keydata_file(off_t file_size, char *file_data)
fheader = (TDEFileHeader *) file_data; fheader = (TDEFileHeader *) file_data;
/* Set the file paths */ /* Set the file paths */
pg_tde_set_db_file_path(fheader->principal_key_info.databaseId, db_map_path); pg_tde_set_db_file_path(fheader->signed_key_info.data.databaseId, db_map_path);
/* Initialize the new file and set the name */ /* Initialize the new file and set the name */
fd_new = keyrotation_init_file(&fheader->principal_key_info, path_new, db_map_path, &curr_pos); fd_new = keyrotation_init_file(&fheader->signed_key_info, path_new, db_map_path, &curr_pos);
if (pg_pwrite(fd_new, file_data, file_size, 0) != file_size) if (pg_pwrite(fd_new, file_data, file_size, 0) != file_size)
{ {
@ -867,7 +897,7 @@ pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path)
* is raised. * is raised.
*/ */
static int static int
pg_tde_open_file_write(const char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool truncate, off_t *curr_pos) pg_tde_open_file_write(const char *tde_filename, const TDESignedPrincipalKeyInfo *signed_key_info, bool truncate, off_t *curr_pos)
{ {
int fd; int fd;
TDEFileHeader fheader; TDEFileHeader fheader;
@ -882,8 +912,8 @@ pg_tde_open_file_write(const char *tde_filename, TDEPrincipalKeyInfo *principal_
pg_tde_file_header_read(tde_filename, fd, &fheader, &bytes_read); pg_tde_file_header_read(tde_filename, fd, &fheader, &bytes_read);
/* In case it's a new file, let's add the header now. */ /* In case it's a new file, let's add the header now. */
if (bytes_read == 0 && principal_key_info) if (bytes_read == 0 && signed_key_info)
pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written); pg_tde_file_header_write(tde_filename, fd, signed_key_info, &bytes_written);
*curr_pos = bytes_read + bytes_written; *curr_pos = bytes_read + bytes_written;
return fd; return fd;
@ -990,6 +1020,12 @@ pg_tde_find_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_
} }
} }
bool
pg_tde_verify_principal_key_info(TDESignedPrincipalKeyInfo *signed_key_info, const TDEPrincipalKey *principal_key)
{
return AesGcmDecrypt(principal_key->keyData, signed_key_info->sign_iv, (unsigned char *) &signed_key_info->data, sizeof(signed_key_info->data), NULL, 0, NULL, signed_key_info->aead_tag);
}
/* /*
* Decrypts a given key and returns the decrypted one. * Decrypts a given key and returns the decrypted one.
*/ */
@ -1154,12 +1190,12 @@ pg_tde_read_one_map_entry2(int fd, int32 key_index, TDEMapEntry *map_entry, Oid
* Get the principal key from the map file. The caller must hold * Get the principal key from the map file. The caller must hold
* a LW_SHARED or higher lock on files before calling this function. * a LW_SHARED or higher lock on files before calling this function.
*/ */
TDEPrincipalKeyInfo * TDESignedPrincipalKeyInfo *
pg_tde_get_principal_key_info(Oid dbOid) pg_tde_get_principal_key_info(Oid dbOid)
{ {
int fd = -1; int fd = -1;
TDEFileHeader fheader; TDEFileHeader fheader;
TDEPrincipalKeyInfo *principal_key_info = NULL; TDESignedPrincipalKeyInfo *signed_key_info = NULL;
off_t bytes_read = 0; off_t bytes_read = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
@ -1186,11 +1222,11 @@ pg_tde_get_principal_key_info(Oid dbOid)
*/ */
if (bytes_read > 0) if (bytes_read > 0)
{ {
principal_key_info = palloc_object(TDEPrincipalKeyInfo); signed_key_info = palloc_object(TDESignedPrincipalKeyInfo);
*principal_key_info = fheader.principal_key_info; *signed_key_info = fheader.signed_key_info;
} }
return principal_key_info; return signed_key_info;
} }
/* /*

View File

@ -61,7 +61,7 @@ tdeheap_rmgr_redo(XLogReaderState *record)
} }
else if (info == XLOG_TDE_ADD_PRINCIPAL_KEY) else if (info == XLOG_TDE_ADD_PRINCIPAL_KEY)
{ {
TDEPrincipalKeyInfo *mkey = (TDEPrincipalKeyInfo *) XLogRecGetData(record); TDESignedPrincipalKeyInfo *mkey = (TDESignedPrincipalKeyInfo *) XLogRecGetData(record);
pg_tde_save_principal_key_redo(mkey); pg_tde_save_principal_key_redo(mkey);
} }
@ -107,7 +107,7 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
{ {
XLogRelKey *xlrec = (XLogRelKey *) XLogRecGetData(record); XLogRelKey *xlrec = (XLogRelKey *) XLogRecGetData(record);
appendStringInfo(buf, "add tde internal key for relation %u/%u", xlrec->pkInfo.databaseId, xlrec->mapEntry.relNumber); appendStringInfo(buf, "add tde internal key for relation %u/%u", xlrec->pkInfo.data.databaseId, xlrec->mapEntry.relNumber);
} }
if (info == XLOG_TDE_ADD_PRINCIPAL_KEY) if (info == XLOG_TDE_ADD_PRINCIPAL_KEY)
{ {

View File

@ -343,7 +343,7 @@ set_principal_key_with_keyring(const char *key_name, const char *provider_name,
if (!already_has_key) if (!already_has_key)
{ {
/* First key created for the database */ /* First key created for the database */
pg_tde_save_principal_key(&new_principal_key->keyInfo); pg_tde_save_principal_key(new_principal_key);
/* XLog the new key */ /* XLog the new key */
XLogBeginInsert(); XLogBeginInsert();
@ -703,7 +703,7 @@ pg_tde_get_key_info(PG_FUNCTION_ARGS, Oid dbOid)
static TDEPrincipalKey * static TDEPrincipalKey *
get_principal_key_from_keyring(Oid dbOid) get_principal_key_from_keyring(Oid dbOid)
{ {
TDEPrincipalKeyInfo *principalKeyInfo; TDESignedPrincipalKeyInfo *principalKeyInfo;
GenericKeyring *keyring; GenericKeyring *keyring;
KeyInfo *keyInfo; KeyInfo *keyInfo;
KeyringReturnCodes keyring_ret; KeyringReturnCodes keyring_ret;
@ -715,28 +715,34 @@ get_principal_key_from_keyring(Oid dbOid)
if (principalKeyInfo == NULL) if (principalKeyInfo == NULL)
return NULL; return NULL;
keyring = GetKeyProviderByID(principalKeyInfo->keyringId, dbOid); keyring = GetKeyProviderByID(principalKeyInfo->data.keyringId, dbOid);
if (keyring == NULL) if (keyring == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED), (errcode(ERRCODE_DATA_CORRUPTED),
errmsg("keyring lookup failed for principal key %s, unknown keyring with ID %d", errmsg("keyring lookup failed for principal key %s, unknown keyring with ID %d",
principalKeyInfo->name, principalKeyInfo->keyringId))); principalKeyInfo->data.name, principalKeyInfo->data.keyringId)));
keyInfo = KeyringGetKey(keyring, principalKeyInfo->name, &keyring_ret); keyInfo = KeyringGetKey(keyring, principalKeyInfo->data.name, &keyring_ret);
if (keyInfo == NULL) if (keyInfo == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NO_DATA_FOUND), (errcode(ERRCODE_NO_DATA_FOUND),
errmsg("failed to retrieve principal key %s from keyring with ID %d", errmsg("failed to retrieve principal key %s from keyring with ID %d",
principalKeyInfo->name, principalKeyInfo->keyringId))); principalKeyInfo->data.name, principalKeyInfo->data.keyringId)));
principalKey = palloc_object(TDEPrincipalKey); principalKey = palloc_object(TDEPrincipalKey);
principalKey->keyInfo = *principalKeyInfo; principalKey->keyInfo = principalKeyInfo->data;
memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len);
principalKey->keyLength = keyInfo->data.len; principalKey->keyLength = keyInfo->data.len;
Assert(dbOid == principalKey->keyInfo.databaseId); Assert(dbOid == principalKey->keyInfo.databaseId);
if (!pg_tde_verify_principal_key_info(principalKeyInfo, principalKey))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("Failed to verify principal key header for key %s, incorrect principal key or corrupted key file",
principalKeyInfo->data.name)));
pfree(keyInfo); pfree(keyInfo);
pfree(keyring); pfree(keyring);
pfree(principalKeyInfo); pfree(principalKeyInfo);
@ -833,7 +839,7 @@ GetPrincipalKey(Oid dbOid, LWLockMode lockMode)
*newPrincipalKey = *principalKey; *newPrincipalKey = *principalKey;
newPrincipalKey->keyInfo.databaseId = dbOid; newPrincipalKey->keyInfo.databaseId = dbOid;
pg_tde_save_principal_key(&newPrincipalKey->keyInfo); pg_tde_save_principal_key(newPrincipalKey);
push_principal_key_to_cache(newPrincipalKey); push_principal_key_to_cache(newPrincipalKey);

View File

@ -46,6 +46,13 @@ typedef struct InternalKey
#define MAP_ENTRY_EMPTY_IV_SIZE 16 #define MAP_ENTRY_EMPTY_IV_SIZE 16
#define MAP_ENTRY_EMPTY_AEAD_TAG_SIZE 16 #define MAP_ENTRY_EMPTY_AEAD_TAG_SIZE 16
typedef struct
{
TDEPrincipalKeyInfo data;
unsigned char sign_iv[16];
unsigned char aead_tag[16];
} TDESignedPrincipalKeyInfo;
/* We do not need the dbOid since the entries are stored in a file per db */ /* We do not need the dbOid since the entries are stored in a file per db */
typedef struct TDEMapEntry typedef struct TDEMapEntry
{ {
@ -61,7 +68,7 @@ typedef struct TDEMapEntry
typedef struct XLogRelKey typedef struct XLogRelKey
{ {
TDEMapEntry mapEntry; TDEMapEntry mapEntry;
TDEPrincipalKeyInfo pkInfo; TDESignedPrincipalKeyInfo pkInfo;
} XLogRelKey; } XLogRelKey;
/* /*
@ -95,7 +102,7 @@ extern void pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path
extern InternalKey *pg_tde_create_smgr_key(const RelFileLocatorBackend *newrlocator); extern InternalKey *pg_tde_create_smgr_key(const RelFileLocatorBackend *newrlocator);
extern void pg_tde_create_wal_key(InternalKey *rel_key_data, const RelFileLocator *newrlocator, uint32 flags); extern void pg_tde_create_wal_key(InternalKey *rel_key_data, const RelFileLocator *newrlocator, uint32 flags);
extern void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset); extern void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset);
extern void pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDEPrincipalKeyInfo *principal_key_info); extern void pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDESignedPrincipalKeyInfo *signed_key_info);
#define PG_TDE_MAP_FILENAME "pg_tde_%d_map" #define PG_TDE_MAP_FILENAME "pg_tde_%d_map"
@ -109,9 +116,10 @@ extern InternalKey *GetSMGRRelationKey(RelFileLocatorBackend rel);
extern void pg_tde_delete_tde_files(Oid dbOid); extern void pg_tde_delete_tde_files(Oid dbOid);
extern TDEPrincipalKeyInfo *pg_tde_get_principal_key_info(Oid dbOid); extern TDESignedPrincipalKeyInfo *pg_tde_get_principal_key_info(Oid dbOid);
extern void pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info); extern bool pg_tde_verify_principal_key_info(TDESignedPrincipalKeyInfo *signed_key_info, const TDEPrincipalKey *principal_key);
extern void pg_tde_save_principal_key_redo(TDEPrincipalKeyInfo *principal_key_info); extern void pg_tde_save_principal_key(const TDEPrincipalKey *principal_key);
extern void pg_tde_save_principal_key_redo(const TDESignedPrincipalKeyInfo *signed_key_info);
extern void pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key); extern void pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key);
extern void pg_tde_write_map_keydata_file(off_t size, char *file_data); extern void pg_tde_write_map_keydata_file(off_t size, char *file_data);

View File

@ -174,15 +174,13 @@ PGTDE::append_to_file($stderr);
(undef, $stdout, $stderr) = $node->psql('postgres', 'SELECT * FROM test_enc ORDER BY id;', extra_params => ['-a']); (undef, $stdout, $stderr) = $node->psql('postgres', 'SELECT * FROM test_enc ORDER BY id;', extra_params => ['-a']);
PGTDE::append_to_file($stdout); PGTDE::append_to_file($stdout);
PGTDE::append_to_file($stderr); PGTDE::append_to_file($stderr);
(undef, $stdout, $stderr) = $node->psql('postgres', 'CREATE TABLE test_enc2 (id serial, k integer, PRIMARY KEY (id)) USING tde_heap;', extra_params => ['-a']);
PGTDE::append_to_file($stdout);
PGTDE::append_to_file($stderr);
$stdout = $node->safe_psql('postgres', "SELECT pg_tde_change_key_provider_file('file-vault', '/tmp/change_key_provider_4.per');", extra_params => ['-a']); $stdout = $node->safe_psql('postgres', "SELECT pg_tde_change_key_provider_file('file-vault', '/tmp/change_key_provider_4.per');", extra_params => ['-a']);
PGTDE::append_to_file($stdout); PGTDE::append_to_file($stdout);
# Restart the server
PGTDE::append_to_file("-- server restart");
$rt_value = $node->stop();
$rt_value = $node->start();
# Verify # Verify
$stdout = $node->safe_psql('postgres', "SELECT pg_tde_verify_principal_key();", extra_params => ['-a']); $stdout = $node->safe_psql('postgres', "SELECT pg_tde_verify_principal_key();", extra_params => ['-a']);
PGTDE::append_to_file($stdout); PGTDE::append_to_file($stdout);

View File

@ -80,15 +80,15 @@ SELECT pg_tde_change_key_provider_file('file-vault', '/tmp/change_key_provider_3
1 1
-- server restart -- server restart
SELECT pg_tde_verify_principal_key(); SELECT pg_tde_verify_principal_key();
psql:<stdin>:1: ERROR: Failed to verify principal key header for key test-key, incorrect principal key or corrupted key file
SELECT pg_tde_is_encrypted('test_enc'); SELECT pg_tde_is_encrypted('test_enc');
psql:<stdin>:1: ERROR: Failed to decrypt key, incorrect principal key or corrupted key file psql:<stdin>:1: ERROR: Failed to verify principal key header for key test-key, incorrect principal key or corrupted key file
SELECT * FROM test_enc ORDER BY id; SELECT * FROM test_enc ORDER BY id;
psql:<stdin>:1: ERROR: Failed to decrypt key, incorrect principal key or corrupted key file psql:<stdin>:1: ERROR: Failed to verify principal key header for key test-key, incorrect principal key or corrupted key file
CREATE TABLE test_enc2 (id serial, k integer, PRIMARY KEY (id)) USING tde_heap;
psql:<stdin>:1: ERROR: Failed to verify principal key header for key test-key, incorrect principal key or corrupted key file
SELECT pg_tde_change_key_provider_file('file-vault', '/tmp/change_key_provider_4.per'); SELECT pg_tde_change_key_provider_file('file-vault', '/tmp/change_key_provider_4.per');
1 1
-- server restart
SELECT pg_tde_verify_principal_key(); SELECT pg_tde_verify_principal_key();
SELECT pg_tde_is_encrypted('test_enc'); SELECT pg_tde_is_encrypted('test_enc');