mirror of
https://github.com/postgres/postgres.git
synced 2025-06-04 00:02:37 -04:00
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:
parent
e9d4927b2c
commit
5514727353
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user