PG-1095 Add format validation CI workflow and format sources (#308)

* PG-1095 Add code format validation to CI

* PG-1095 Manually fix some codestyle

* PG-1095 Add comment to pgindent_exclude file

* PG-1095 Format sources

* PG-1095 Fix makefile

* PG-1095 Remove accidentally commited file

* PG-1094 Update gitignore

* PG-1094 Update pgindent_exclude

* PG-1095 Update typedefs list

* PG-1095 Manual code formatting

* PG-1095 Update typedefs list

* PG-1095 More manual code formatting

* PG-1095 More manual code formatting

* PG-1095 More fixes

* PG-1095 Fix
pull/209/head
Artem Gavrilov 10 months ago committed by GitHub
parent 2f31c0ed45
commit d2237acde5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 57
      .github/workflows/check.yaml
  2. 4
      .gitignore
  3. 11
      Makefile.in
  4. 9
      pgindent_excludes
  5. 56
      src/access/pg_tde_ddl.c
  6. 112
      src/access/pg_tde_slot.c
  7. 276
      src/access/pg_tde_tdemap.c
  8. 13
      src/access/pg_tde_xlog.c
  9. 131
      src/access/pg_tde_xlog_encrypt.c
  10. 29
      src/catalog/tde_global_space.c
  11. 171
      src/catalog/tde_keyring.c
  12. 30
      src/catalog/tde_keyring_parse_opts.c
  13. 947
      src/catalog/tde_principal_key.c
  14. 52
      src/common/pg_tde_shmem.c
  15. 101
      src/common/pg_tde_utils.c
  16. 131
      src/encryption/enc_aes.c
  17. 200
      src/encryption/enc_tde.c
  18. 2
      src/include/access/pg_tde_ddl.h
  19. 18
      src/include/access/pg_tde_slot.h
  20. 10
      src/include/access/pg_tde_tdemap.h
  21. 4
      src/include/access/pg_tde_xlog.h
  22. 4
      src/include/access/pg_tde_xlog_encrypt.h
  23. 4
      src/include/access/pg_tde_xlog_encrypt_fe.h
  24. 2
      src/include/catalog/tde_global_space.h
  25. 29
      src/include/catalog/tde_keyring.h
  26. 28
      src/include/catalog/tde_principal_key.h
  27. 59
      src/include/common/pg_tde_shmem.h
  28. 8
      src/include/common/pg_tde_utils.h
  29. 8
      src/include/encryption/enc_aes.h
  30. 16
      src/include/encryption/enc_tde.h
  31. 12
      src/include/keyring/keyring_api.h
  32. 13
      src/include/keyring/keyring_curl.h
  33. 2
      src/include/keyring/keyring_file.h
  34. 2
      src/include/keyring/keyring_vault.h
  35. 10
      src/include/pg_tde.h
  36. 10
      src/include/pg_tde_defines.h
  37. 2
      src/include/pg_tde_defs.h
  38. 12
      src/include/pg_tde_event_capture.h
  39. 2
      src/include/smgr/pg_tde_smgr.h
  40. 4
      src/include/transam/pg_tde_xact_handler.h
  41. 24
      src/keyring/keyring_api.c
  42. 73
      src/keyring/keyring_curl.c
  43. 55
      src/keyring/keyring_file.c
  44. 88
      src/keyring/keyring_vault.c
  45. 39
      src/pg_tde.c
  46. 4
      src/pg_tde_defs.c
  47. 18
      src/pg_tde_event_capture.c
  48. 139
      src/smgr/pg_tde_smgr.c
  49. 166
      src/transam/pg_tde_xact_handler.c
  50. 113
      typedefs.list

@ -0,0 +1,57 @@
name: Checks
on:
pull_request:
jobs:
format:
name: Format
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcurl4-openssl-dev
- name: Clone postgres repository
uses: actions/checkout@v4
with:
repository: 'postgres/postgres'
ref: 'REL_17_STABLE'
- name: Checkout sources
uses: actions/checkout@v4
with:
path: 'contrib/pg_tde'
- name: Configure postgres
run: ./configure
- name: Configure pg_tde
run: ./configure
working-directory: contrib/pg_tde
- name: Install perltidy
run: sudo cpan -T SHANCOCK/Perl-Tidy-20230309.tar.gz
- name: Install pg_bsd_indent
working-directory: src/tools/pg_bsd_indent
run: sudo make install
- name: Add pg_bsd_indent and pgindent to path
run: |
echo "/usr/local/pgsql/bin" >> $GITHUB_PATH
echo "${{ github.workspace }}/src/tools/pgindent" >> $GITHUB_PATH
- name: Format sources
working-directory: contrib/pg_tde
run: |
make update-typedefs
make indent
- name: Check files are formatted and no source code changes
working-directory: contrib/pg_tde
run: |
git status
git diff --exit-code

4
.gitignore vendored

@ -9,3 +9,7 @@ __pycache__
/autom4te.cache
/configure~
t/results
src/include/config.h
# tools files
typedefs-full.list

@ -74,3 +74,14 @@ include $(top_srcdir)/contrib/contrib-global.mk
endif
override SHLIB_LINK += @tde_LDFLAGS@ -lcrypto -lssl
# Fetches typedefs list for PostgreSQL core and merges it with typedefs defined in this project.
# https://wiki.postgresql.org/wiki/Running_pgindent_on_non-core_code_or_development_code
update-typedefs:
wget -q -O - "https://buildfarm.postgresql.org/cgi-bin/typedefs.pl?branch=REL_17_STABLE" | cat - typedefs.list | sort | uniq > typedefs-full.list
# Indents projects sources.
indent:
pgindent --typedefs=typedefs-full.list --excludes=pgindent_excludes .
.PHONY: update-typedefs indent

@ -0,0 +1,9 @@
# List of filename patterns to exclude from pgindent runs
#
# This contains code copied from postgres tree as is and slightly modified.
# We don't want to run pgindent on these files to avoid unnecessary conflicts.
src\d\d/
# This file is generated by configure and should not be formatted
src/include/config.h

@ -20,37 +20,39 @@
static object_access_hook_type prev_object_access_hook = NULL;
static void tdeheap_object_access_hook(ObjectAccessType access, Oid classId,
Oid objectId, int subId, void *arg);
Oid objectId, int subId, void *arg);
void SetupTdeDDLHooks(void)
void
SetupTdeDDLHooks(void)
{
prev_object_access_hook = object_access_hook;
object_access_hook = tdeheap_object_access_hook;
prev_object_access_hook = object_access_hook;
object_access_hook = tdeheap_object_access_hook;
}
static void
tdeheap_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId,
int subId, void *arg)
{
Relation rel = NULL;
if (prev_object_access_hook)
prev_object_access_hook(access, classId, objectId, subId, arg);
if (access == OAT_DROP && classId == RelationRelationId)
{
ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
rel = relation_open(objectId, AccessShareLock);
}
if (rel != NULL)
{
if ((rel->rd_rel->relkind == RELKIND_RELATION ||
rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
rel->rd_rel->relkind == RELKIND_MATVIEW) &&
(subId == 0) && is_tdeheap_rel(rel))
{
pg_tde_delete_key_map_entry(&rel->rd_locator, MAP_ENTRY_VALID);
}
relation_close(rel, AccessShareLock);
}
int subId, void *arg)
{
Relation rel = NULL;
if (prev_object_access_hook)
prev_object_access_hook(access, classId, objectId, subId, arg);
if (access == OAT_DROP && classId == RelationRelationId)
{
ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
rel = relation_open(objectId, AccessShareLock);
}
if (rel != NULL)
{
if ((rel->rd_rel->relkind == RELKIND_RELATION ||
rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
rel->rd_rel->relkind == RELKIND_MATVIEW) &&
(subId == 0) && is_tdeheap_rel(rel))
{
pg_tde_delete_key_map_entry(&rel->rd_locator, MAP_ENTRY_VALID);
}
relation_close(rel, AccessShareLock);
}
}

@ -41,14 +41,15 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple;
static HeapTuple slot_copytuple(void *buffer, HeapTuple tuple);
static pg_attribute_always_inline void tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int natts);
static inline void tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot,
HeapTuple tuple,
Buffer buffer,
bool transfer_pin);
HeapTuple tuple,
Buffer buffer,
bool transfer_pin);
static inline RelKeyData *get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel);
static void
tdeheap_tts_buffer_heap_init(TupleTableSlot *slot)
{
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
bslot->cached_relation_key = NULL;
}
@ -111,34 +112,34 @@ tdeheap_tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnul
*/
if (!bslot->base.tuple)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot retrieve a system column in this context")));
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot retrieve a system column in this context")));
return tdeheap_getsysattr(bslot->base.tuple, attnum,
slot->tts_tupleDescriptor, isnull);
slot->tts_tupleDescriptor, isnull);
}
static bool
tdeheap_buffer_is_current_xact_tuple(TupleTableSlot *slot)
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
TransactionId xmin;
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
TransactionId xmin;
Assert(!TTS_EMPTY(slot));
Assert(!TTS_EMPTY(slot));
/*
* In some code paths it's possible to get here with a non-materialized
* slot, in which case we can't check if tuple is created by the current
* transaction.
*/
if (!bslot->base.tuple)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("don't have a storage tuple in this context")));
/*
* In some code paths it's possible to get here with a non-materialized
* slot, in which case we can't check if tuple is created by the current
* transaction.
*/
if (!bslot->base.tuple)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("don't have a storage tuple in this context")));
xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
return TransactionIdIsCurrentTransactionId(xmin);
return TransactionIdIsCurrentTransactionId(xmin);
}
static void
@ -172,8 +173,8 @@ tdeheap_tts_buffer_heap_materialize(TupleTableSlot *slot)
* materializable.
*/
bslot->base.tuple = tdeheap_form_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
slot->tts_isnull);
slot->tts_values,
slot->tts_isnull);
}
else
{
@ -229,7 +230,7 @@ tdeheap_tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslo
Assert(BufferIsValid(bsrcslot->buffer));
tdeheap_tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
bsrcslot->buffer, false);
bsrcslot->buffer, false);
/*
* The HeapTupleData portion of the source tuple might be shorter
@ -254,6 +255,7 @@ static HeapTuple
tdeheap_tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
Assert(!TTS_EMPTY(slot));
if (!bslot->base.tuple)
@ -289,7 +291,7 @@ tdeheap_tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
static inline void
tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
Buffer buffer, bool transfer_pin)
Buffer buffer, bool transfer_pin)
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
@ -355,18 +357,19 @@ tdeheap_tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
*/
static pg_attribute_always_inline void
tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
int natts)
int natts)
{
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
Datum *values = slot->tts_values;
bool *isnull = slot->tts_isnull;
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
Datum *values = slot->tts_values;
bool *isnull = slot->tts_isnull;
HeapTupleHeader tup = tuple->t_data;
bool hasnulls = HeapTupleHasNulls(tuple);
int attnum;
char *tp; /* ptr to tuple data */
uint32 off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
bool slow; /* can we use/set attcacheoff? */
bool hasnulls = HeapTupleHasNulls(tuple);
int attnum;
char *tp; /* ptr to tuple data */
uint32 off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
bool slow; /* can we use/set attcacheoff? */
/* We can only fetch as many attributes as the tuple has. */
natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
@ -453,9 +456,9 @@ tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *of
}
static HeapTuple
slot_copytuple(void* buffer, HeapTuple tuple)
slot_copytuple(void *buffer, HeapTuple tuple)
{
HeapTuple newTuple;
HeapTuple newTuple;
if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
return NULL;
@ -465,7 +468,7 @@ slot_copytuple(void* buffer, HeapTuple tuple)
newTuple->t_self = tuple->t_self;
newTuple->t_tableOid = tuple->t_tableOid;
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
// We don't copy the data, it will be copied by the decryption code
/* We don't copy the data, it will be copied by the decryption code */
memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_data->t_hoff);
return newTuple;
}
@ -487,7 +490,8 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple = {
/* A buffer heap tuple table slot can not "own" a minimal tuple. */
.get_minimal_tuple = NULL,
.copy_heap_tuple = tdeheap_tts_buffer_heap_copy_heap_tuple,
.copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple};
.copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple
};
/* --------------------------------
* ExecStoreBufferHeapTuple
@ -510,12 +514,13 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple = {
*/
TupleTableSlot *
PGTdeExecStoreBufferHeapTuple(Relation rel,
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer)
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer)
{
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *)slot;
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/*
* sanity checks
*/
@ -535,8 +540,8 @@ PGTdeExecStoreBufferHeapTuple(Relation rel,
Assert(key != NULL);
slot_copytuple(bslot->decrypted_buffer, tuple);
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple)bslot->decrypted_buffer, key, "ExecStoreBuffer");
tuple->t_data = ((HeapTuple)bslot->decrypted_buffer)->t_data;
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple) bslot->decrypted_buffer, key, "ExecStoreBuffer");
tuple->t_data = ((HeapTuple) bslot->decrypted_buffer)->t_data;
}
tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
@ -552,11 +557,12 @@ PGTdeExecStoreBufferHeapTuple(Relation rel,
*/
TupleTableSlot *
PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer)
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer)
{
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *)slot;
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/*
* sanity checks
*/
@ -571,12 +577,12 @@ PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
if (rel->rd_rel->relkind != RELKIND_TOASTVALUE)
{
RelKeyData *key = get_current_slot_relation_key(bslot,rel);
RelKeyData *key = get_current_slot_relation_key(bslot, rel);
slot_copytuple(bslot->decrypted_buffer, tuple);
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple)bslot->decrypted_buffer, key, "ExecStorePinnedBuffer");
PG_TDE_DECRYPT_TUPLE_EX(tuple, (HeapTuple) bslot->decrypted_buffer, key, "ExecStorePinnedBuffer");
/* TODO: revisit this */
tuple->t_data = ((HeapTuple)bslot->decrypted_buffer)->t_data;
tuple->t_data = ((HeapTuple) bslot->decrypted_buffer)->t_data;
}
tdeheap_tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
@ -586,7 +592,7 @@ PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
return slot;
}
static inline RelKeyData*
static inline RelKeyData *
get_current_slot_relation_key(TDEBufferHeapTupleTableSlot *bslot, Relation rel)
{
Assert(bslot != NULL);

@ -55,14 +55,14 @@
}
#endif
#define PG_TDE_MAP_FILENAME "pg_tde.map"
#define PG_TDE_KEYDATA_FILENAME "pg_tde.dat"
#define PG_TDE_MAP_FILENAME "pg_tde.map"
#define PG_TDE_KEYDATA_FILENAME "pg_tde.dat"
#define PG_TDE_FILEMAGIC 0x01454454 /* version ID value = TDE 01 */
#define PG_TDE_FILEMAGIC 0x01454454 /* version ID value = TDE 01 */
#define MAP_ENTRY_SIZE sizeof(TDEMapEntry)
#define TDE_FILE_HEADER_SIZE sizeof(TDEFileHeader)
#define MAP_ENTRY_SIZE sizeof(TDEMapEntry)
#define TDE_FILE_HEADER_SIZE sizeof(TDEFileHeader)
typedef struct TDEFileHeader
{
@ -90,34 +90,34 @@ typedef struct RelKeyCacheRec
RelKeyData key;
} RelKeyCacheRec;
/*
/*
* Relation keys cache.
*
*
* This is a slice backed by memory `*data`. Initially, we allocate one memory
* page (usually 4Kb). We reallocate it by adding another page when we run out
* of space. This memory is locked in the RAM so it won't be paged to the swap
* of space. This memory is locked in the RAM so it won't be paged to the swap
* (we don't want decrypted keys on disk). We do allocations in mem pages as
* these are the units `mlock()` operations are performed in.
*
* Currently, the cache can only grow (no eviction). The data is located in
*
* Currently, the cache can only grow (no eviction). The data is located in
* TopMemoryContext hence being wiped when the process exits, as well as memory
* is being unlocked by OS.
*/
typedef struct RelKeyCache
{
RelKeyCacheRec *data; /* must be a multiple of a memory page (usually 4Kb) */
int len; /* num of RelKeyCacheRecs currenty in cache */
int cap; /* max amount of RelKeyCacheRec data can fit */
int len; /* num of RelKeyCacheRecs currenty in cache */
int cap; /* max amount of RelKeyCacheRec data can fit */
} RelKeyCache;
RelKeyCache *tde_rel_key_cache = NULL;
static int32 pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *db_map_path, off_t *offset, bool should_delete);
static RelKeyData* pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key);
static RelKeyData *pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key);
static int pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing);
static int pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read);
static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
static RelKeyData* pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key);
static RelKeyData *pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key);
static int pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset);
static RelKeyData *pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type);
@ -160,7 +160,7 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type
RelKeyData *enc_rel_key_data;
TDEPrincipalKey *principal_key;
XLogRelKey xlrec;
LWLock *lock_pk = tde_lwlock_enc_keys();
LWLock *lock_pk = tde_lwlock_enc_keys();
LWLockAcquire(lock_pk, LW_EXCLUSIVE);
principal_key = GetPrincipalKey(newrlocator->dbOid, newrlocator->spcOid, LW_EXCLUSIVE);
@ -182,8 +182,8 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator, uint32 entry_type
LWLockRelease(lock_pk);
ereport(FATAL,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate internal key for relation \"%s\": %s",
"TODO", ERR_error_string(ERR_get_error(), NULL))));
errmsg("could not generate internal key for relation \"%s\": %s",
"TODO", ERR_error_string(ERR_get_error(), NULL))));
return NULL;
}
@ -215,10 +215,10 @@ const char *
tde_sprint_key(InternalKey *k)
{
static char buf[256];
int i;
int i;
for (i = 0; i < sizeof(k->key); i++)
sprintf(buf+i, "%02X", k->key[i]);
sprintf(buf + i, "%02X", k->key[i]);
return buf;
}
@ -230,7 +230,8 @@ tde_sprint_key(InternalKey *k)
RelKeyData *
tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info)
{
RelKeyData rel_key_data;
RelKeyData rel_key_data;
memcpy(&rel_key_data.principal_key_id, &principal_key_info->keyId, sizeof(TDEPrincipalKeyId));
memcpy(&rel_key_data.internal_key, key, sizeof(InternalKey));
rel_key_data.internal_key.ctx = NULL;
@ -238,6 +239,7 @@ tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo
/* Add to the decrypted key to cache */
return pg_tde_put_key_into_cache(rel_num, &rel_key_data);
}
/*
* Encrypts a given key and returns the encrypted one.
*/
@ -287,13 +289,13 @@ pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info)
off_t curr_pos = 0;
bool is_new_map = false;
bool is_new_key_data = false;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(principal_key_info->databaseId,
principal_key_info->tablespaceId,
db_map_path, db_keydata_path);
principal_key_info->tablespaceId,
db_map_path, db_keydata_path);
ereport(LOG, (errmsg("pg_tde_save_principal_key")));
@ -333,7 +335,7 @@ pg_tde_file_header_write(char *tde_filename, int fd, TDEPrincipalKeyInfo *princi
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
tde_filename)));
}
@ -363,7 +365,7 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
int32 key_index = 0;
TDEMapEntry map_entry;
bool is_new_file;
off_t curr_pos = 0;
off_t curr_pos = 0;
off_t prev_pos = 0;
bool found = false;
@ -373,15 +375,18 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
/*
* Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather
* than overloading the vacuum process.
* to be less frequent than vacuum. So let's keep this function here
* rather than overloading the vacuum process.
*/
while(1)
while (1)
{
prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &map_entry, &curr_pos);
/* We either reach EOF or found an empty slot in the middle of the file */
/*
* We either reach EOF or found an empty slot in the middle of the
* file
*/
if (prev_pos == curr_pos || found)
break;
@ -389,7 +394,10 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
key_index++;
}
/* Write the given entry at the location pointed by prev_pos; i.e. the free entry */
/*
* Write the given entry at the location pointed by prev_pos; i.e. the
* free entry
*/
curr_pos = prev_pos;
pg_tde_write_one_map_entry(map_fd, rlocator, entry_type, key_index, &map_entry, &prev_pos);
@ -425,15 +433,17 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, uint32 flags,
if (bytes_written != MAP_ENTRY_SIZE)
{
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not write tde map file \"%s\": %m",
errmsg("could not write tde map file \"%s\": %m",
db_map_path)));
}
if (pg_fsync(fd) != 0)
{
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(),
@ -487,7 +497,7 @@ pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data)
{
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not write tde key data file: %m")));
errmsg("could not write tde key data file: %m")));
}
if (pg_fsync(fd) != 0)
@ -508,9 +518,9 @@ pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data)
void
pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_key_data, TDEPrincipalKeyInfo *principal_key_info)
{
int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
@ -528,13 +538,14 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_k
* Deletes a map entry by setting marking it as unused. We don't have to delete
* the actual key data as valid key data entries are identify by valid map entries.
*/
void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type)
void
pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type)
{
int32 key_index = 0;
off_t offset = 0;
LWLock *lock_files = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
int32 key_index = 0;
off_t offset = 0;
LWLock *lock_files = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
@ -544,14 +555,14 @@ void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type
errno = 0;
/* Remove the map entry if found */
LWLockAcquire(lock_files, LW_EXCLUSIVE);
key_index = pg_tde_process_map_entry(rlocator, key_type, db_map_path, &offset, false);
key_index = pg_tde_process_map_entry(rlocator, key_type, db_map_path, &offset, false);
LWLockRelease(lock_files);
if (key_index == -1)
{
ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber,
db_map_path)));
@ -575,7 +586,8 @@ void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type
*
* A caller should hold an EXCLUSIVE tde_lwlock_enc_keys lock.
*/
void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset)
void
pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset)
{
int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0};
@ -593,7 +605,7 @@ void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type,
{
ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber,
db_map_path)));
@ -621,7 +633,10 @@ void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type,
static File
keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos)
{
/* Set the new filenames for the key rotation process - temporary at the moment */
/*
* Set the new filenames for the key rotation process - temporary at the
* moment
*/
snprintf(rotated_filename, MAXPGPATH, "%s.r", filename);
/* Create file, truncate if the rotate file already exits */
@ -649,13 +664,13 @@ finalize_key_rotation(char *m_path_old, char *k_path_old, char *m_path_new, char
bool
pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key)
{
#define OLD_PRINCIPAL_KEY 0
#define NEW_PRINCIPAL_KEY 1
#define OLD_PRINCIPAL_KEY 0
#define NEW_PRINCIPAL_KEY 1
#define PRINCIPAL_KEY_COUNT 2
off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0};
off_t prev_pos[PRINCIPAL_KEY_COUNT] = {0};
int32 key_index[PRINCIPAL_KEY_COUNT] = {0};
off_t curr_pos[PRINCIPAL_KEY_COUNT] = {0};
off_t prev_pos[PRINCIPAL_KEY_COUNT] = {0};
int32 key_index[PRINCIPAL_KEY_COUNT] = {0};
RelKeyData *rel_key_data[PRINCIPAL_KEY_COUNT];
RelKeyData *enc_rel_key_data[PRINCIPAL_KEY_COUNT];
int m_fd[PRINCIPAL_KEY_COUNT] = {-1};
@ -668,20 +683,26 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
off_t map_size;
off_t keydata_size;
XLogPrincipalKeyRotate *xlrec;
off_t xlrec_size;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
off_t xlrec_size;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId,
principal_key->keyInfo.tablespaceId,
db_map_path, db_keydata_path);
principal_key->keyInfo.tablespaceId,
db_map_path, db_keydata_path);
/* Let's update the pathnames in the local variable for ease of use/readability */
/*
* Let's update the pathnames in the local variable for ease of
* use/readability
*/
strncpy(m_path[OLD_PRINCIPAL_KEY], db_map_path, MAXPGPATH);
strncpy(k_path[OLD_PRINCIPAL_KEY], db_keydata_path, MAXPGPATH);
/* Open both files in read only mode. We don't need to track the current position of the keydata file. We always use the key index */
/*
* Open both files in read only mode. We don't need to track the current
* position of the keydata file. We always use the key index
*/
m_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(m_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_PRINCIPAL_KEY]);
k_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(k_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp);
@ -689,9 +710,10 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
k_fd[NEW_PRINCIPAL_KEY] = keyrotation_init_file(&new_principal_key->keyInfo, k_path[NEW_PRINCIPAL_KEY], k_path[OLD_PRINCIPAL_KEY], &is_new_file, &read_pos_tmp);
/* Read all entries until EOF */
for(key_index[OLD_PRINCIPAL_KEY] = 0; ; key_index[OLD_PRINCIPAL_KEY]++)
for (key_index[OLD_PRINCIPAL_KEY] = 0;; key_index[OLD_PRINCIPAL_KEY]++)
{
TDEMapEntry read_map_entry, write_map_entry;
TDEMapEntry read_map_entry,
write_map_entry;
RelFileLocator rloc;
prev_pos[OLD_PRINCIPAL_KEY] = curr_pos[OLD_PRINCIPAL_KEY];
@ -705,14 +727,17 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
if (found == false)
continue;
/* Set the relNumber of rlocator. Ignore the tablespace Oid since we only place our files under the default. */
/*
* Set the relNumber of rlocator. Ignore the tablespace Oid since we
* only place our files under the default.
*/
rloc.relNumber = read_map_entry.relNumber;
rloc.dbOid = principal_key->keyInfo.databaseId;
rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit*/
rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit */
/* Let's get the decrypted key and re-encrypt it with the new key. */
enc_rel_key_data[OLD_PRINCIPAL_KEY] = pg_tde_read_one_keydata(k_fd[OLD_PRINCIPAL_KEY], key_index[OLD_PRINCIPAL_KEY], principal_key);
/* Decrypt and re-encrypt keys */
rel_key_data[OLD_PRINCIPAL_KEY] = tde_decrypt_rel_key(principal_key, enc_rel_key_data[OLD_PRINCIPAL_KEY], &rloc);
enc_rel_key_data[NEW_PRINCIPAL_KEY] = tde_encrypt_rel_key(new_principal_key, rel_key_data[OLD_PRINCIPAL_KEY], &rloc);
@ -777,24 +802,24 @@ bool
pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_size, char *k_file_data)
{
TDEFileHeader *fheader;
char m_path_new[MAXPGPATH];
char k_path_new[MAXPGPATH];
int m_fd_new;
int k_fd_new;
bool is_new_file;
off_t curr_pos = 0;
off_t read_pos_tmp = 0;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
bool is_err = false;
char m_path_new[MAXPGPATH];
char k_path_new[MAXPGPATH];
int m_fd_new;
int k_fd_new;
bool is_new_file;
off_t curr_pos = 0;
off_t read_pos_tmp = 0;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
bool is_err = false;
/* Let's get the header. Buff should start with the map file header. */
fheader = (TDEFileHeader *) m_file_data;
/* Set the file paths */
pg_tde_set_db_file_paths(fheader->principal_key_info.databaseId,
fheader->principal_key_info.tablespaceId,
db_map_path, db_keydata_path);
fheader->principal_key_info.tablespaceId,
db_map_path, db_keydata_path);
/* Initialize the new files and set the names */
m_fd_new = keyrotation_init_file(&fheader->principal_key_info, m_path_new, db_map_path, &is_new_file, &curr_pos);
@ -805,7 +830,7 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
m_path_new)));
is_err = true;
goto FINALIZE;
@ -824,7 +849,7 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
k_path_new)));
is_err = true;
goto FINALIZE;
@ -938,29 +963,28 @@ pg_tde_move_rel_key(const RelFileLocator *newrlocator, const RelFileLocator *old
RelKeyData *
pg_tde_get_key_from_file(const RelFileLocator *rlocator, uint32 key_type, bool no_map_ok)
{
int32 key_index = 0;
TDEPrincipalKey *principal_key;
RelKeyData *rel_key_data;
RelKeyData *enc_rel_key_data;
off_t offset = 0;
LWLock *lock_pk = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
int32 key_index = 0;
TDEPrincipalKey *principal_key;
RelKeyData *rel_key_data;
RelKeyData *enc_rel_key_data;
off_t offset = 0;
LWLock *lock_pk = tde_lwlock_enc_keys();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
/*
/*
* Get/generate a principal key, create the key for relation and get the
* encrypted key with bytes to write
*
*
* We should hold the lock until the internal key is loaded to be sure the
* retrieved key was encrypted with the obtained principal key. Otherwise,
* the next may happen:
* - GetPrincipalKey returns key "PKey_1".
* - Some other process rotates the Principal key and re-encrypt an
* Internal key with "PKey_2".
* - We read the Internal key and decrypt it with "PKey_1" (that's what
* we've got). As the result we return an invalid Internal key.
* the next may happen: - GetPrincipalKey returns key "PKey_1". - Some
* other process rotates the Principal key and re-encrypt an Internal key
* with "PKey_2". - We read the Internal key and decrypt it with "PKey_1"
* (that's what we've got). As the result we return an invalid Internal
* key.
*/
LWLockAcquire(lock_pk, LW_SHARED);
principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid, LW_SHARED);
@ -1031,8 +1055,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
Assert(offset);
/*
* Open and validate file for basic correctness. DO NOT create it.
* The file should pre-exist otherwise we should never be here.
* Open and validate file for basic correctness. DO NOT create it. The
* file should pre-exist otherwise we should never be here.
*/
map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos);
@ -1049,8 +1073,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
{
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not seek in tde map file \"%s\": %m",
db_map_path)));
errmsg("could not seek in tde map file \"%s\": %m",
db_map_path)));
}
}
else
@ -1061,10 +1085,10 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
/*
* Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather
* than overloading the vacuum process.
* to be less frequent than vacuum. So let's keep this function here
* rather than overloading the vacuum process.
*/
while(1)
while (1)
{
prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_fd, rlocator, key_type, &map_entry, &curr_pos);
@ -1175,7 +1199,7 @@ pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bo
/* In case it's a new file, let's add the header now. */
if (*is_new_file && principal_key_info)
pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written);
#endif /* FRONTEND */
#endif /* FRONTEND */
*curr_pos = bytes_read + bytes_written;
return fd;
@ -1227,13 +1251,13 @@ pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool
return fd;
if (*bytes_read != TDE_FILE_HEADER_SIZE
|| fheader->file_version != PG_TDE_FILEMAGIC)
|| fheader->file_version != PG_TDE_FILEMAGIC)
{
/* Corrupt file */
ereport(FATAL,
(errcode_for_file_access(),
errmsg("TDE map file \"%s\" is corrupted: %m",
tde_filename)));
tde_filename)));
}
return fd;
@ -1300,10 +1324,11 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
if ((read_pos + INTERNAL_KEY_DAT_LEN) > lseek(keydata_fd, 0, SEEK_END))
{
char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("could not find the required key at index %d in tde data file \"%s\": %m",
errmsg("could not find the required key at index %d in tde data file \"%s\": %m",
key_index,
db_keydata_path)));
}
@ -1312,11 +1337,12 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_DAT_LEN, read_pos) != INTERNAL_KEY_DAT_LEN)
{
char db_keydata_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not read key at index %d in tde key data file \"%s\": %m",
errmsg("could not read key at index %d in tde key data file \"%s\": %m",
key_index,
db_keydata_path)));
}
@ -1337,7 +1363,7 @@ pg_tde_get_principal_key_info(Oid dbOid, Oid spcOid)
TDEPrincipalKeyInfo *principal_key_info = NULL;
bool is_new_file = false;
off_t bytes_read = 0;
char db_map_path[MAXPGPATH] = {0};
char db_map_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(dbOid, spcOid, db_map_path, NULL);
@ -1356,7 +1382,10 @@ pg_tde_get_principal_key_info(Oid dbOid, Oid spcOid)
close(fd);
/* It's not a new file. So we can memcpy the principal key info from the header */
/*
* It's not a new file. So we can memcpy the principal key info from the
* header
*/
if (!is_new_file)
{
size_t sz = sizeof(TDEPrincipalKeyInfo);
@ -1420,14 +1449,14 @@ GetTdeGlobaleRelationKey(RelFileLocator rel)
static RelKeyData *
pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type)
{
RelKeyCacheRec *rec;
RelKeyCacheRec *rec;
if (tde_rel_key_cache == NULL)
return NULL;
for (int i = 0; i < tde_rel_key_cache->len; i++)
{
rec = tde_rel_key_cache->data+i;
rec = tde_rel_key_cache->data + i;
if (rec != NULL &&
(rel_number == InvalidOid || (rec->rel_number == rel_number)) &&
rec->key.internal_key.rel_type & key_type)
@ -1440,23 +1469,23 @@ pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type)
}
/* Add key to cache. See comments on `RelKeyCache`.
*
*
* TODO: add tests.
*/
RelKeyData *
pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
{
static long pageSize = 0;
RelKeyCacheRec *rec;
MemoryContext oldCtx;
static long pageSize = 0;
RelKeyCacheRec *rec;
MemoryContext oldCtx;
if (pageSize == 0)
{
#ifndef _SC_PAGESIZE
pageSize = getpagesize();
#else
#else
pageSize = sysconf(_SC_PAGESIZE);
#endif
#endif
}
if (tde_rel_key_cache == NULL)
@ -1479,17 +1508,18 @@ pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
tde_rel_key_cache->cap = pageSize / sizeof(RelKeyCacheRec);
}
/* Add another mem page if there is no more room left for another key. We
/*
* Add another mem page if there is no more room left for another key. We
* allocate `current_memory_size` + 1 page and copy data there.
*/
if (tde_rel_key_cache->len+1 >
if (tde_rel_key_cache->len + 1 >
(tde_rel_key_cache->cap * sizeof(RelKeyCacheRec)) / sizeof(RelKeyCacheRec))
{
size_t size;
size_t old_size;
RelKeyCacheRec *chachePage;
RelKeyCacheRec *chachePage;
size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap+1) * sizeof(RelKeyCacheRec));
size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap + 1) * sizeof(RelKeyCacheRec));
old_size = TYPEALIGN(pageSize, (tde_rel_key_cache->cap) * sizeof(RelKeyCacheRec));
#ifndef FRONTEND
@ -1518,4 +1548,4 @@ pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
tde_rel_key_cache->len++;
return &rec->key;
}
}

@ -33,7 +33,7 @@
void
tdeheap_rmgr_redo(XLogReaderState *record)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
if (info == XLOG_TDE_ADD_RELATION_KEY)
{
@ -57,14 +57,15 @@ tdeheap_rmgr_redo(XLogReaderState *record)
}
else if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
{
XLogExtensionInstall *xlrec = (XLogExtensionInstall *)XLogRecGetData(record);
XLogExtensionInstall *xlrec = (XLogExtensionInstall *) XLogRecGetData(record);
extension_install_redo(xlrec);
}
else if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY)
{
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *)XLogRecGetData(record);
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record);
redo_key_provider_info(xlrec);
}
@ -95,7 +96,7 @@ tdeheap_rmgr_redo(XLogReaderState *record)
void
tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
if (info == XLOG_TDE_ADD_RELATION_KEY)
{
@ -111,7 +112,7 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
}
if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
{
XLogExtensionInstall *xlrec = (XLogExtensionInstall *)XLogRecGetData(record);
XLogExtensionInstall *xlrec = (XLogExtensionInstall *) XLogRecGetData(record);
appendStringInfo(buf, "tde extension install for db %u/%u", xlrec->database_id, xlrec->tablespace_id);
}
@ -123,7 +124,7 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)
}
if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY)
{
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *)XLogRecGetData(record);
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record);
appendStringInfo(buf, "add key provider %s for %u", xlrec->provider.provider_name, xlrec->database_id);
}

@ -34,7 +34,7 @@
static XLogPageHeaderData DecryptCurrentPageHrd;
static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix);
static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char *iv_prefix);
#ifndef FRONTEND
/* GUC */
@ -52,8 +52,8 @@ XLogInitGUC(void)
DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */
"Enable/Disable encryption of WAL.", /* short_desc */
NULL, /* long_desc */
&EncryptXLog, /* value address */
false, /* boot value */
&EncryptXLog, /* value address */
false, /* boot value */
PGC_POSTMASTER, /* context */
0, /* flags */
NULL, /* check_hook */
@ -65,7 +65,7 @@ XLogInitGUC(void)
static int
XLOGChooseNumBuffers(void)
{
int xbuffers;
int xbuffers;
xbuffers = NBuffers / 32;
if (xbuffers > (wal_segment_size / XLOG_BLCKSZ))
@ -75,72 +75,72 @@ XLOGChooseNumBuffers(void)
return xbuffers;
}
/*
/*
* Defines the size of the XLog encryption buffer
*/
Size
TDEXLogEncryptBuffSize(void)
{
int xbuffers;
int xbuffers;
xbuffers = (XLOGbuffers == -1) ? XLOGChooseNumBuffers() : XLOGbuffers;
return (Size) XLOG_BLCKSZ * xbuffers;
}
/*
/*
* Alloc memory for the encryption buffer.
*
*
* It should fit XLog buffers (XLOG_BLCKSZ * wal_buffers). We can't
* (re)alloc this buf in tdeheap_xlog_seg_write() based on the write size as
* it's called in the CRIT section, hence no allocations are allowed.
*
*
* Access to this buffer happens during XLogWrite() call which should
* be called with WALWriteLock held, hence no need in extra locks.
*/
void
TDEXLogShmemInit(void)
{
bool foundBuf;
bool foundBuf;
if (EncryptXLog)
{
TDEXLogEncryptBuf = (char *)
TYPEALIGN(PG_IO_ALIGN_SIZE,
ShmemInitStruct("TDE XLog Encryption Buffer",
XLOG_TDE_ENC_BUFF_ALIGNED_SIZE,
&foundBuf));
ShmemInitStruct("TDE XLog Encryption Buffer",
XLOG_TDE_ENC_BUFF_ALIGNED_SIZE,
&foundBuf));
elog(DEBUG1, "pg_tde: initialized encryption buffer %lu bytes", XLOG_TDE_ENC_BUFF_ALIGNED_SIZE);
}
}
/*
/*
* Encrypt XLog page(s) from the buf and write to the segment file.
*/
static ssize_t
TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
{
char iv_prefix[16] = {0,};
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd;
XLogPageHeader enc_buf_page;
char iv_prefix[16] = {0,};
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd;
XLogPageHeader enc_buf_page;
RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID));
off_t enc_off;
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
uint32 iv_ctr = 0;
off_t enc_off;
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
uint32 iv_ctr = 0;
#ifdef TDE_XLOG_DEBUG
elog(DEBUG1, "write encrypted WAL, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset);
#endif
/*
* Go through the buf page-by-page and encrypt them.
* We may start or finish writing from/in the middle of the page
* (walsender or `full_page_writes = off`). So preserve a page header
* for the IV init data.
*
* TODO: check if walsender restarts form the beggining of the page
* in case of the crash.
* Go through the buf page-by-page and encrypt them. We may start or
* finish writing from/in the middle of the page (walsender or
* `full_page_writes = off`). So preserve a page header for the IV init
* data.
*
* TODO: check if walsender restarts form the beggining of the page in
* case of the crash.
*/
for (enc_off = 0; enc_off < count;)
{
@ -150,9 +150,10 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
{
memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD);
/*
* Need to use a separate buf for the encryption so the page remains non-crypted
* in the XLog buf (XLogInsert has to have access to records' lsn).
/*
* Need to use a separate buf for the encryption so the page
* remains non-crypted in the XLog buf (XLogInsert has to have
* access to records' lsn).
*/
enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off);
memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr));
@ -163,35 +164,35 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
/* it's a beginning of the page */
iv_ctr = 0;
}
else
else
{
/* we're in the middle of the page */
iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr);
}
if (data_size + enc_off > count)
if (data_size + enc_off > count)
{
data_size = count - enc_off;
}
/*
* The page is zeroed (no data), no sense to enctypt.
* This may happen when base_backup or other requests XLOG SWITCH and
* some pages in XLog buffer still not used.
*/
/*
* The page is zeroed (no data), no sense to enctypt. This may happen
* when base_backup or other requests XLOG SWITCH and some pages in
* XLog buffer still not used.
*/
if (curr_page_hdr->xlp_magic == 0)
{
/* ensure all the page is {0} */
Assert((*((char *) buf + enc_off) == 0) &&
memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0);
Assert((*((char *) buf + enc_off) == 0) &&
memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0);
memcpy((char *) enc_buf_page, (char *) buf + enc_off, data_size);
}
else
{
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_ENCRYPT_DATA(iv_prefix, iv_ctr, (char *) buf + enc_off, data_size,
TDEXLogEncryptBuf + enc_off, key);
PG_TDE_ENCRYPT_DATA(iv_prefix, iv_ctr, (char *) buf + enc_off, data_size,
TDEXLogEncryptBuf + enc_off, key);
}
page_size = XLOG_BLCKSZ;
@ -200,7 +201,7 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
return pg_pwrite(fd, TDEXLogEncryptBuf, count, offset);
}
#endif /* !FRONTEND */
#endif /* !FRONTEND */
void
TDEXLogSmgrInit(void)
@ -219,20 +220,20 @@ tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset)
return pg_pwrite(fd, buf, count, offset);
}
/*
/*
* Read the XLog pages from the segment file and dectypt if need.
*/
ssize_t
tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
{
ssize_t readsz;
char iv_prefix[16] = {0,};
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd;
char iv_prefix[16] = {0,};
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd;
RelKeyData *key = GetTdeGlobaleRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID));
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
off_t dec_off;
uint32 iv_ctr = 0;
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
off_t dec_off;
uint32 iv_ctr = 0;
#ifdef TDE_XLOG_DEBUG
elog(DEBUG1, "read from a WAL segment, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset);
@ -240,14 +241,14 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
readsz = pg_pread(fd, buf, count, offset);
/*
* Read the buf page by page and decypt ecnrypted pages.
* We may start or fihish reading from/in the middle of the page (walreceiver)
* in such a case we should preserve the last read page header for
* the IV data and the encryption state.
*
* TODO: check if walsender/receiver restarts form the beggining of the page
* in case of the crash.
/*
* Read the buf page by page and decypt ecnrypted pages. We may start or
* fihish reading from/in the middle of the page (walreceiver) in such a
* case we should preserve the last read page header for the IV data and
* the encryption state.
*
* TODO: check if walsender/receiver restarts form the beggining of the
* page in case of the crash.
*/
for (dec_off = 0; dec_off < readsz;)
{
@ -266,13 +267,13 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
/* it's a beginning of the page */
iv_ctr = 0;
}
else
else
{
/* we're in the middle of the page */
iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr);
}
if ((data_size + dec_off) > readsz)
if ((data_size + dec_off) > readsz)
{
data_size = readsz - dec_off;
}
@ -281,10 +282,10 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
{
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_DECRYPT_DATA(
iv_prefix, iv_ctr,
(char *) buf + dec_off, data_size, (char *) buf + dec_off, key);
iv_prefix, iv_ctr,
(char *) buf + dec_off, data_size, (char *) buf + dec_off, key);
}
page_size = XLOG_BLCKSZ;
dec_off += data_size;
}
@ -294,7 +295,7 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
/* IV: TLI(uint32) + XLogRecPtr(uint64)*/
static void
SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix)
SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char *iv_prefix)
{
iv_prefix[0] = (tli >> 24);
iv_prefix[1] = ((tli >> 16) & 0xFF);
@ -311,4 +312,4 @@ SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix)
iv_prefix[11] = (lsn & 0xFF);
}
#endif /* PERCONA_EXT */
#endif /* PERCONA_EXT */

@ -41,19 +41,19 @@
#ifndef FRONTEND
static void init_keys(void);
static void init_default_keyring(void);
static TDEPrincipalKey * create_principal_key(const char *key_name,
GenericKeyring * keyring, Oid dbOid,
Oid spcOid);
#endif /* !FRONTEND */
static TDEPrincipalKey *create_principal_key(const char *key_name,
GenericKeyring *keyring, Oid dbOid,
Oid spcOid);
#endif /* !FRONTEND */
void
TDEInitGlobalKeys(const char *dir)
{
#ifndef FRONTEND
char db_map_path[MAXPGPATH] = {0};
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID, db_map_path, NULL);
pg_tde_set_db_file_paths(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID, db_map_path, NULL);
if (access(db_map_path, F_OK) == -1)
{
init_default_keyring();
@ -89,23 +89,23 @@ init_default_keyring(void)
{
if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL)
{
char path[MAXPGPATH] = {0};
char path[MAXPGPATH] = {0};
static KeyringProvideRecord provider =
{
.provider_name = KEYRING_DEFAULT_NAME,
.provider_type = FILE_KEY_PROVIDER,
.provider_type = FILE_KEY_PROVIDER,
};
if (getcwd(path, sizeof(path)) == NULL)
elog(WARNING, "unable to get current working dir");
/* TODO: not sure about the location. Currently it's in $PGDATA */
join_path_components(path, path, KEYRING_DEFAULT_FILE_NAME);
snprintf(provider.options, MAX_KEYRING_OPTION_LEN,
"{"
"\"type\": \"file\","
"\"path\": \"%s\""
"\"path\": \"%s\""
"}", path
);
@ -175,11 +175,11 @@ init_keys(void)
* first.
*/
static TDEPrincipalKey *
create_principal_key(const char *key_name, GenericKeyring * keyring,
create_principal_key(const char *key_name, GenericKeyring *keyring,
Oid dbOid, Oid spcOid)
{
TDEPrincipalKey *principalKey;
keyInfo *keyInfo = NULL;
keyInfo *keyInfo = NULL;
principalKey = palloc(sizeof(TDEPrincipalKey));
principalKey->keyInfo.databaseId = dbOid;
@ -200,10 +200,11 @@ create_principal_key(const char *key_name, GenericKeyring * keyring,
}
principalKey->keyLength = keyInfo->data.len;
memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len);
return principalKey;
}
#endif /* FRONTEND */
#endif /* FRONTEND */
#endif /* PERCONA_EXT */
#endif /* PERCONA_EXT */

@ -37,7 +37,7 @@
#else
#include "fe_utils/simple_list.h"
#include "pg_tde_fe.h"
#endif /* !FRONTEND */
#endif /* !FRONTEND */
typedef enum ProviderScanType
{
@ -55,7 +55,7 @@ static VaultV2Keyring *load_vaultV2_keyring_provider_options(char *keyring_optio
static void debug_print_kerying(GenericKeyring *keyring);
static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider);
static char *get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid);
static bool fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider);
static bool fetch_next_key_provider(int fd, off_t *curr_pos, KeyringProvideRecord *provider);
#ifdef FRONTEND
@ -89,14 +89,14 @@ typedef struct TdeKeyProviderInfoSharedState
LWLockPadded *Locks;
} TdeKeyProviderInfoSharedState;
TdeKeyProviderInfoSharedState* sharedPrincipalKeyState = NULL; /* Lives in shared state */
TdeKeyProviderInfoSharedState *sharedPrincipalKeyState = NULL; /* Lives in shared state */
static const TDEShmemSetupRoutine key_provider_info_shmem_routine = {
.init_shared_state = initialize_shared_state,
.init_dsa_area_objects = NULL,
.required_shared_mem_size = required_shared_mem_size,
.shmem_kill = NULL
};
};
static Size
required_shared_mem_size(void)
@ -107,7 +107,7 @@ required_shared_mem_size(void)
static Size
initialize_shared_state(void *start_address)
{
sharedPrincipalKeyState = (TdeKeyProviderInfoSharedState *)start_address;
sharedPrincipalKeyState = (TdeKeyProviderInfoSharedState *) start_address;
sharedPrincipalKeyState->Locks = GetNamedLWLockTranche(TDE_TRANCHE_NAME);
return sizeof(TdeKeyProviderInfoSharedState);
@ -120,7 +120,8 @@ tde_provider_info_lock(void)
return &sharedPrincipalKeyState->Locks[TDE_LWLOCK_PI_FILES].lock;
}
void InitializeKeyProviderInfo(void)
void
InitializeKeyProviderInfo(void)
{
ereport(LOG, (errmsg("initializing TDE key provider info")));
RegisterShmemRequest(&key_provider_info_shmem_routine);
@ -157,12 +158,12 @@ get_keyring_provider_typename(ProviderType p_type)
{
switch (p_type)
{
case FILE_KEY_PROVIDER:
return FILE_KEYRING_TYPE;
case VAULT_V2_KEY_PROVIDER:
return VAULTV2_KEYRING_TYPE;
default:
break;
case FILE_KEY_PROVIDER:
return FILE_KEYRING_TYPE;
case VAULT_V2_KEY_PROVIDER:
return VAULTV2_KEYRING_TYPE;
default:
break;
}
return NULL;
}
@ -177,10 +178,11 @@ GenericKeyring *
GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid)
{
GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void*)provider_name, dbOid, spcOid);
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void *) provider_name, dbOid, spcOid);
if (providers != NIL)
{
keyring = (GenericKeyring *)linitial(providers);
keyring = (GenericKeyring *) linitial(providers);
list_free(providers);
}
else
@ -216,12 +218,15 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
{
LWLockRelease(tde_provider_info_lock());
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path)));
(errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path)));
}
if (position == -1)
{
/* we also need to verify the name conflict and generate the next provider ID */
/*
* we also need to verify the name conflict and generate the next
* provider ID
*/
while (fetch_next_key_provider(fd, &curr_pos, &existing_provider))
{
if (strcmp(existing_provider.provider_name, provider->provider_name) == 0)
@ -244,7 +249,8 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
provider->provider_id = max_provider_id + 1;
curr_pos = lseek(fd, 0, SEEK_END);
/* emit the xlog here. So that we can handle partial file write errors
/*
* emit the xlog here. So that we can handle partial file write errors
* but cannot make new WAL entries during recovery.
*/
if (write_xlog)
@ -257,18 +263,20 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
memcpy(&xlrec.provider, provider, sizeof(KeyringProvideRecord));
XLogBeginInsert();
XLogRegisterData((char *)&xlrec, sizeof(KeyringProviderXLRecord));
XLogRegisterData((char *) &xlrec, sizeof(KeyringProviderXLRecord));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_ADD_KEY_PROVIDER_KEY);
}
}
else
{
/* we are performing redo, just go to the position received from the
* xlog and write the record there.
* No need to verify the name conflict and generate the provider ID
/*
* we are performing redo, just go to the position received from the
* xlog and write the record there. No need to verify the name
* conflict and generate the provider ID
*/
curr_pos = lseek(fd, position, SEEK_SET);
}
/*
* All good, Just add a new provider
*/
@ -315,7 +323,7 @@ copy_key_provider_info(KeyringProvideRecord* provider, Oid newdatabaseId, Oid ne
}
uint32
redo_key_provider_info(KeyringProviderXLRecord* xlrec)
redo_key_provider_info(KeyringProviderXLRecord *xlrec)
{
return write_key_provider_info(&xlrec->provider, xlrec->database_id, xlrec->tablespace_id, xlrec->offset_in_file, true, false);
}
@ -324,7 +332,7 @@ void
cleanup_key_provider_info(Oid databaseId, Oid tablespaceId)
{
/* Remove the key provider info file */
char kp_info_path[MAXPGPATH] = {0};
char kp_info_path[MAXPGPATH] = {0};
get_keyring_infofile_path(kp_info_path, databaseId, tablespaceId);
PathNameDeleteTemporaryFile(kp_info_path, false);
@ -358,13 +366,14 @@ pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS)
Datum
pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
{
List* all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace);
List *all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace);
ListCell *lc;
Tuplestorestate *tupstore;
TupleDesc tupdesc;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
@ -390,11 +399,11 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext);
foreach (lc, all_providers)
foreach(lc, all_providers)
{
Datum values[PG_TDE_LIST_PROVIDERS_COLS] = {0};
bool nulls[PG_TDE_LIST_PROVIDERS_COLS] = {0};
GenericKeyring *keyring = (GenericKeyring *)lfirst(lc);
GenericKeyring *keyring = (GenericKeyring *) lfirst(lc);
int i = 0;
values[i++] = Int32GetDatum(keyring->key_id);
@ -406,7 +415,7 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
debug_print_kerying(keyring);
}
list_free_deep(all_providers);
return (Datum)0;
return (Datum) 0;
}
GenericKeyring *
@ -414,15 +423,16 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{
GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NIL)
{
keyring = (GenericKeyring *)linitial(providers);
keyring = (GenericKeyring *) linitial(providers);
list_free(providers);
}
return keyring;
}
#endif /* !FRONTEND */
#endif /* !FRONTEND */
#ifdef FRONTEND
GenericKeyring *
@ -430,6 +440,7 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{
GenericKeyring *keyring = NULL;
SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NULL)
{
keyring = (GenericKeyring *) providers->head->ptr;
@ -453,7 +464,7 @@ simple_list_free(SimplePtrList *list)
cell = next;
}
}
#endif /* FRONTEND */
#endif /* FRONTEND */
/*
* Scan the key provider info file and can also apply filter based on scanType
@ -487,29 +498,30 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
{
LWLockRelease(tde_provider_info_lock());
ereport(DEBUG2,
(errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path)));
(errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path)));
return providers_list;
}
while (fetch_next_key_provider(fd, &curr_pos, &provider))
{
bool match = false;
bool match = false;
ereport(DEBUG2,
(errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name)));
(errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name)));
if (scanType == PROVIDER_SCAN_BY_NAME)
{
if (strcasecmp(provider.provider_name, (char*)scanKey) == 0)
if (strcasecmp(provider.provider_name, (char *) scanKey) == 0)
match = true;
}
else if (scanType == PROVIDER_SCAN_BY_ID)
{
if (provider.provider_id == *(int *)scanKey)
if (provider.provider_id == *(int *) scanKey)
match = true;
}
else if (scanType == PROVIDER_SCAN_BY_TYPE)
{
if (provider.provider_type == *(ProviderType*)scanKey)
if (provider.provider_type == *(ProviderType *) scanKey)
match = true;
}
else if (scanType == PROVIDER_SCAN_ALL)
@ -518,6 +530,7 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
if (match)
{
GenericKeyring *keyring = load_keyring_provider_from_record(&provider);
if (keyring)
{
#ifndef FRONTEND
@ -558,14 +571,14 @@ load_keyring_provider_options(ProviderType provider_type, char *keyring_options)
{
switch (provider_type)
{
case FILE_KEY_PROVIDER:
return (GenericKeyring *)load_file_keyring_provider_options(keyring_options);
break;
case VAULT_V2_KEY_PROVIDER:
return (GenericKeyring *)load_vaultV2_keyring_provider_options(keyring_options);
break;
default:
break;
case FILE_KEY_PROVIDER:
return (GenericKeyring *) load_file_keyring_provider_options(keyring_options);
break;
case VAULT_V2_KEY_PROVIDER:
return (GenericKeyring *) load_vaultV2_keyring_provider_options(keyring_options);
break;
default:
break;
}
return NULL;
}
@ -573,17 +586,17 @@ load_keyring_provider_options(ProviderType provider_type, char *keyring_options)
static FileKeyring *
load_file_keyring_provider_options(char *keyring_options)
{
FileKeyring *file_keyring = palloc0(sizeof(FileKeyring));
FileKeyring *file_keyring = palloc0(sizeof(FileKeyring));
file_keyring->keyring.type = FILE_KEY_PROVIDER;
if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring,
keyring_options, strlen(keyring_options)))
if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring,
keyring_options, strlen(keyring_options)))
{
return NULL;
}
if(strlen(file_keyring->file_name) == 0)
if (strlen(file_keyring->file_name) == 0)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -597,26 +610,26 @@ load_file_keyring_provider_options(char *keyring_options)
static VaultV2Keyring *
load_vaultV2_keyring_provider_options(char *keyring_options)
{
VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring));
VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring));
vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER;
if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring,
keyring_options, strlen(keyring_options)))
if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring,
keyring_options, strlen(keyring_options)))
{
return NULL;
}
if(strlen(vaultV2_keyring->vault_token) == 0 ||
strlen(vaultV2_keyring->vault_url) == 0 ||
if (strlen(vaultV2_keyring->vault_token) == 0 ||
strlen(vaultV2_keyring->vault_url) == 0 ||
strlen(vaultV2_keyring->vault_mount_path) == 0)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing in the keyring options:%s%s%s",
*(vaultV2_keyring->vault_token) ? "" : " token",
*(vaultV2_keyring->vault_url) ? "" : " url",
*(vaultV2_keyring->vault_mount_path) ? "" : " mountPath")));
*(vaultV2_keyring->vault_token) ? "" : " token",
*(vaultV2_keyring->vault_url) ? "" : " url",
*(vaultV2_keyring->vault_mount_path) ? "" : " mountPath")));
return NULL;
}
@ -627,30 +640,32 @@ static void
debug_print_kerying(GenericKeyring *keyring)
{
int debug_level = DEBUG2;
elog(debug_level, "Keyring type: %d", keyring->type);
elog(debug_level, "Keyring name: %s", keyring->provider_name);
elog(debug_level, "Keyring id: %d", keyring->key_id);
switch (keyring->type)
{
case FILE_KEY_PROVIDER:
elog(debug_level, "File Keyring Path: %s", ((FileKeyring *)keyring)->file_name);
break;
case VAULT_V2_KEY_PROVIDER:
elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *)keyring)->vault_token);
elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *)keyring)->vault_url);
elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *)keyring)->vault_mount_path);
elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *)keyring)->vault_ca_path);
break;
case UNKNOWN_KEY_PROVIDER:
elog(debug_level, "Unknown Keyring ");
break;
case FILE_KEY_PROVIDER:
elog(debug_level, "File Keyring Path: %s", ((FileKeyring *) keyring)->file_name);
break;
case VAULT_V2_KEY_PROVIDER:
elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *) keyring)->vault_token);
elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *) keyring)->vault_url);
elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *) keyring)->vault_mount_path);
elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *) keyring)->vault_ca_path);
break;
case UNKNOWN_KEY_PROVIDER:
elog(debug_level, "Unknown Keyring ");
break;
}
}
static char*
get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid)
static char *
get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid)
{
char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid);
Assert(db_path != NULL);
join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME);
pfree(db_path);
@ -661,7 +676,7 @@ get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid)
* Fetch the next key provider from the file and update the curr_pos
*/
static bool
fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider)
fetch_next_key_provider(int fd, off_t *curr_pos, KeyringProvideRecord *provider)
{
off_t bytes_read = 0;
@ -679,8 +694,8 @@ fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider)
/* Corrupt file */
ereport(ERROR,
(errcode_for_file_access(),
errmsg("key provider info file is corrupted: %m"),
errdetail("invalid key provider record size %lld expected %lu", bytes_read, sizeof(KeyringProvideRecord) )));
errmsg("key provider info file is corrupted: %m"),
errdetail("invalid key provider record size %lld expected %lu", bytes_read, sizeof(KeyringProvideRecord))));
}
return true;
}
}

@ -2,7 +2,7 @@
*
* tde_keyring_parse_opts.c
* Parser routines for the keyring JSON options
*
*
* Each value in the JSON document can be either scalar (string) - a value itself
* or a reference to the external object that contains the value. Though the top
* level field "type" can be only scalar.
@ -47,7 +47,7 @@ typedef enum JsonKeringSemState
{
JK_EXPECT_TOP_FIELD,
JK_EXPECT_EXTERN_VAL,
} JsonKeringSemState;
} JsonKeringSemState;
#define KEYRING_REMOTE_FIELD_TYPE "remote"
#define KEYRING_FILE_FIELD_TYPE "file"
@ -71,7 +71,7 @@ typedef enum JsonKeyringField
/* must be the last */
JK_FIELDS_TOTAL
} JsonKeyringField;
} JsonKeyringField;
static const char *JK_FIELD_NAMES[JK_FIELDS_TOTAL] = {
[JK_FIELD_UNKNOWN] = "unknownField",
@ -100,7 +100,7 @@ typedef struct JsonKeyringState
* Caller's options to be set from JSON values. Expected either
* `VaultV2Keyring` or `FileKeyring`
*/
void *provider_opts;
void *provider_opts;
/*
* A field hierarchy of the current branch, field[level] is the current
@ -109,25 +109,25 @@ typedef struct JsonKeyringState
*/
JsonKeyringField field[MAX_JSON_DEPTH];
JsonKeringSemState state;
int level;
int level;
/*
* The rest of the scalar fields might be in the JSON document but has no
* direct value for the caller. Although we need them for the values
* extraction or state tracking.
*/
char *kring_type;
char *field_type;
char *extern_url;
char *extern_path;
} JsonKeyringState;
char *kring_type;
char *field_type;
char *extern_url;
char *extern_path;
} JsonKeyringState;
static JsonParseErrorType json_kring_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType json_kring_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType json_kring_object_start(void *state);
static JsonParseErrorType json_kring_object_end(void *state);
static void json_kring_assign_scalar(JsonKeyringState * parse, JsonKeyringField field, char *value);
static void json_kring_assign_scalar(JsonKeyringState *parse, JsonKeyringField field, char *value);
static char *get_remote_kring_value(const char *url, const char *field_name);
static char *get_file_kring_value(const char *path, const char *field_name);
@ -364,7 +364,7 @@ json_kring_scalar(void *state, char *token, JsonTokenType tokentype)
}
static void
json_kring_assign_scalar(JsonKeyringState * parse, JsonKeyringField field, char *value)
json_kring_assign_scalar(JsonKeyringState *parse, JsonKeyringField field, char *value)
{
VaultV2Keyring *vault = parse->provider_opts;
FileKeyring *file = parse->provider_opts;
@ -437,15 +437,15 @@ get_remote_kring_value(const char *url, const char *field_name)
/* remove trailing whitespace */
outStr.ptr[strcspn(outStr.ptr, " \t\n\r")] = '\0';
return outStr.ptr;
}
static char *
get_file_kring_value(const char *path, const char *field_name)
{
int fd = -1;
char *val;
int fd = -1;
char *val;
fd = BasicOpenFile(path, O_RDONLY);
if (fd < 0)

File diff suppressed because it is too large Load Diff

@ -19,16 +19,15 @@ typedef struct TdeSharedState
{
LWLock *principalKeyLock;
int principalKeyHashTrancheId;
void *rawDsaArea; /* DSA area pointer to store cache hashes */
void *rawDsaArea; /* DSA area pointer to store cache hashes */
dshash_table_handle principalKeyHashHandle;
} TdeSharedState;
typedef struct TDELocalState
{
TdeSharedState *sharedTdeState;
dsa_area **dsa; /* local dsa area for backend attached to the
* dsa area created by postmaster at startup.
*/
dsa_area **dsa; /* local dsa area for backend attached to the
* dsa area created by postmaster at startup. */
dshash_table *principalKeySharedHash;
} TDELocalState;
@ -37,19 +36,23 @@ static void tde_shmem_shutdown(int code, Datum arg);
List *registeredShmemRequests = NIL;
bool shmemInited = false;
void RegisterShmemRequest(const TDEShmemSetupRoutine *routine)
void
RegisterShmemRequest(const TDEShmemSetupRoutine *routine)
{
Assert(shmemInited == false);
registeredShmemRequests = lappend(registeredShmemRequests, (void *)routine);
registeredShmemRequests = lappend(registeredShmemRequests, (void *) routine);
}
Size TdeRequiredSharedMemorySize(void)
Size
TdeRequiredSharedMemorySize(void)
{
Size sz = 0;
ListCell *lc;
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc);
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->required_shared_mem_size)
sz = add_size(sz, routine->required_shared_mem_size());
}
@ -57,12 +60,14 @@ Size TdeRequiredSharedMemorySize(void)
return MAXALIGN(sz);
}
int TdeRequiredLocksCount(void)
int
TdeRequiredLocksCount(void)
{
return TDE_LWLOCK_COUNT;
}
void TdeShmemInit(void)
void
TdeShmemInit(void)
{
bool found;
TdeSharedState *tdeState;
@ -76,7 +81,7 @@ void TdeShmemInit(void)
if (!found)
{
/* First time through ... */
char *p = (char *)tdeState;
char *p = (char *) tdeState;
dsa_area *dsa;
ListCell *lc;
Size used_size = 0;
@ -85,10 +90,11 @@ void TdeShmemInit(void)
p += MAXALIGN(sizeof(TdeSharedState));
used_size += MAXALIGN(sizeof(TdeSharedState));
/* Now place all shared state structures */
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{
Size sz = 0;
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc);
Size sz = 0;
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_shared_state)
{
sz = routine->init_shared_state(p);
@ -110,29 +116,33 @@ void TdeShmemInit(void)
dsa_set_size_limit(dsa, dsa_area_size);
/* Initialize all DSA area objects */
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc);
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_dsa_area_objects)
routine->init_dsa_area_objects(dsa, tdeState->rawDsaArea);
}
ereport(LOG, (errmsg("setting no limit to DSA area of size %lu", dsa_area_size)));
dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared memory */
dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared
* memory */
shmemInited = true;
}
LWLockRelease(AddinShmemInitLock);
on_shmem_exit(tde_shmem_shutdown, (Datum)0);
on_shmem_exit(tde_shmem_shutdown, (Datum) 0);
}
static void
tde_shmem_shutdown(int code, Datum arg)
{
ListCell *lc;
foreach (lc, registeredShmemRequests)
foreach(lc, registeredShmemRequests)
{
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *)lfirst(lc);
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->shmem_kill)
routine->shmem_kill(code, arg);
}

@ -23,89 +23,92 @@
Oid
get_tde_basic_table_am_oid(void)
{
return get_table_am_oid("tde_heap_basic", false);
return get_table_am_oid("tde_heap_basic", false);
}
Oid
get_tde_table_am_oid(void)
{
return get_table_am_oid("tde_heap", false);
return get_table_am_oid("tde_heap", false);
}
/*
* Returns the list of OIDs for all TDE tables in a database
*/
List*
List *
get_all_tde_tables(void)
{
Relation pg_class;
SysScanDesc scan;
HeapTuple tuple;
List* tde_tables = NIL;
Oid am_oid = get_tde_basic_table_am_oid();
/* Open the pg_class table */
pg_class = table_open(RelationRelationId, AccessShareLock);
/* Start a scan */
scan = systable_beginscan(pg_class, ClassOidIndexId, true,
SnapshotSelf, 0, NULL);
/* Iterate over all tuples in the table */
while ((tuple = systable_getnext(scan)) != NULL)
{
Form_pg_class classForm = (Form_pg_class)GETSTRUCT(tuple);
/* Check if the table uses the specified access method */
if (classForm->relam == am_oid)
{
/* Print the name of the table */
tde_tables = lappend_oid(tde_tables, classForm->oid);
elog(DEBUG2, "Table %s uses the TDE access method.", NameStr(classForm->relname));
}
}
/* End the scan */
systable_endscan(scan);
/* Close the pg_class table */
table_close(pg_class, AccessShareLock);
return tde_tables;
Relation pg_class;
SysScanDesc scan;
HeapTuple tuple;
List *tde_tables = NIL;
Oid am_oid = get_tde_basic_table_am_oid();
/* Open the pg_class table */
pg_class = table_open(RelationRelationId, AccessShareLock);
/* Start a scan */
scan = systable_beginscan(pg_class, ClassOidIndexId, true,
SnapshotSelf, 0, NULL);
/* Iterate over all tuples in the table */
while ((tuple = systable_getnext(scan)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
/* Check if the table uses the specified access method */
if (classForm->relam == am_oid)
{
/* Print the name of the table */
tde_tables = lappend_oid(tde_tables, classForm->oid);
elog(DEBUG2, "Table %s uses the TDE access method.", NameStr(classForm->relname));
}
}
/* End the scan */
systable_endscan(scan);
/* Close the pg_class table */
table_close(pg_class, AccessShareLock);
return tde_tables;
}
int
get_tde_tables_count(void)
{
List* tde_tables = get_all_tde_tables();
int count = list_length(tde_tables);
list_free(tde_tables);
return count;
List *tde_tables = get_all_tde_tables();
int count = list_length(tde_tables);
list_free(tde_tables);
return count;
}
#endif /* !FRONTEND */
#endif /* !FRONTEND */
static char globalspace_dir[MAXPGPATH] = {0};
void
pg_tde_set_globalspace_dir(const char *dir)
{
Assert(dir != NULL);
strncpy(globalspace_dir, dir, sizeof(globalspace_dir));
Assert(dir != NULL);
strncpy(globalspace_dir, dir, sizeof(globalspace_dir));
}
/* returns the palloc'd string */
char *
pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid)
{
/* `dbOid` is set to a value for the XLog keys caching but GetDatabasePath()
* expects it (`dbOid`) to be `0` if this is a global space.
/*
* `dbOid` is set to a value for the XLog keys caching but
* GetDatabasePath() expects it (`dbOid`) to be `0` if this is a global
* space.
*/
if (spcOid == GLOBALTABLESPACE_OID)
{
if (strlen(globalspace_dir) > 0)
return pstrdup(globalspace_dir);
{
if (strlen(globalspace_dir) > 0)
return pstrdup(globalspace_dir);
return pstrdup("global");
}
}
return GetDatabasePath(dbOid, spcOid);
}

@ -39,48 +39,51 @@
* * When a new block is requested, we use this stored context to encrypt the position information
* * And then XOR it with the data
*
* This is still not as fast as using 8k blocks, but already 2 orders of magnitude better than direct CTR with
* This is still not as fast as using 8k blocks, but already 2 orders of magnitude better than direct CTR with
* 16 byte blocks.
*/
const EVP_CIPHER* cipher = NULL;
const EVP_CIPHER* cipher2 = NULL;
int cipher_block_size = 0;
const EVP_CIPHER *cipher = NULL;
const EVP_CIPHER *cipher2 = NULL;
int cipher_block_size = 0;
void AesInit(void)
void
AesInit(void)
{
static int initialized = 0;
if(!initialized) {
if (!initialized)
{
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
cipher = EVP_aes_128_cbc();
cipher_block_size = EVP_CIPHER_block_size(cipher); // == buffer size
cipher2 = EVP_aes_128_ecb();
cipher_block_size = EVP_CIPHER_block_size(cipher);
//== buffer size
cipher2 = EVP_aes_128_ecb();
initialized = 1;
}
}
// TODO: a few things could be optimized in this. It's good enough for a prototype.
/* TODO: a few things could be optimized in this. It's good enough for a prototype. */
static void
AesRunCtr(EVP_CIPHER_CTX** ctxPtr, int enc, const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len)
AesRunCtr(EVP_CIPHER_CTX **ctxPtr, int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{
if (*ctxPtr == NULL)
{
*ctxPtr = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(*ctxPtr);
if(EVP_CipherInit_ex(*ctxPtr, cipher2, NULL, key, iv, enc) == 0)
if (EVP_CipherInit_ex(*ctxPtr, cipher2, NULL, key, iv, enc) == 0)
{
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
(errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif
#endif
return;
}
@ -88,103 +91,109 @@ AesRunCtr(EVP_CIPHER_CTX** ctxPtr, int enc, const unsigned char* key, const unsi
EVP_CIPHER_CTX_set_padding(*ctxPtr, 0);
}
if(EVP_CipherUpdate(*ctxPtr, out, out_len, in, in_len) == 0)
if (EVP_CipherUpdate(*ctxPtr, out, out_len, in, in_len) == 0)
{
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
(errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif
#endif
return;
}
}
static void AesRunCbc(int enc, const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len)
static void
AesRunCbc(int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{
int out_len_final = 0;
EVP_CIPHER_CTX* ctx = NULL;
int out_len_final = 0;
EVP_CIPHER_CTX *ctx = NULL;
ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
if(EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 0)
if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) == 0)
{
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
(errmsg("EVP_CipherInit_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif
#endif
goto cleanup;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
Assert(in_len % cipher_block_size == 0);
if(EVP_CipherUpdate(ctx, out, out_len, in, in_len) == 0)
if (EVP_CipherUpdate(ctx, out, out_len, in, in_len) == 0)
{
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
(errmsg("EVP_CipherUpdate failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif
#endif
goto cleanup;
}
if(EVP_CipherFinal_ex(ctx, out + *out_len, &out_len_final) == 0)
if (EVP_CipherFinal_ex(ctx, out + *out_len, &out_len_final) == 0)
{
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
#ifdef FRONTEND
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
#else
ereport(ERROR,
(errmsg("EVP_CipherFinal_ex failed. OpenSSL error: %s", ERR_error_string(ERR_get_error(), NULL))));
#endif
#endif
goto cleanup;
}
/* We encrypt one block (16 bytes)
* Our expectation is that the result should also be 16 bytes, without any additional padding
/*
* We encrypt one block (16 bytes) Our expectation is that the result
* should also be 16 bytes, without any additional padding
*/
*out_len += out_len_final;
Assert(in_len == *out_len);
cleanup:
EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx);
EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx);
}
void AesEncrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len)
void
AesEncrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{
AesRunCbc(1, key, iv, in, in_len, out, out_len);
}
void AesDecrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len)
void
AesDecrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{
AesRunCbc(0, key, iv, in, in_len, out, out_len);
}
/* This function assumes that the out buffer is big enough: at least (blockNumber2 - blockNumber1) * 16 bytes
*/
void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const char* iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char* out)
void
Aes128EncryptedZeroBlocks(void *ctxPtr, const unsigned char *key, const char *iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char *out)
{
const unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned dataLen = (blockNumber2 - blockNumber1) * 16;
int outLen;
int outLen;
Assert(blockNumber2 >= blockNumber1);
for(int j=blockNumber1;j<blockNumber2;++j)
for (int j = blockNumber1; j < blockNumber2; ++j)
{
/*
* We have 16 bytes, and a 4 byte counter. The counter is the last 4 bytes.
* Technically, this isn't correct: the byte order of the counter depends
* on the endianness of the CPU running it.
* As this is a generic limitation of Postgres, it's fine.
* We have 16 bytes, and a 4 byte counter. The counter is the last 4
* bytes. Technically, this isn't correct: the byte order of the
* counter depends on the endianness of the CPU running it. As this is
* a generic limitation of Postgres, it's fine.
*/
memcpy(out + (16*(j-blockNumber1)), iv_prefix, 12);
memcpy(out + (16*(j-blockNumber1)) + 12, (char*)&j, 4);
memcpy(out + (16 * (j - blockNumber1)), iv_prefix, 12);
memcpy(out + (16 * (j - blockNumber1)) + 12, (char *) &j, 4);
}
AesRunCtr(ctxPtr, 1, key, iv, out, dataLen, out, &outLen);

@ -11,23 +11,26 @@
#include "keyring/keyring_api.h"
#ifdef ENCRYPTION_DEBUG
static void iv_prefix_debug(const char* iv_prefix, char* out_hex)
static void
iv_prefix_debug(const char *iv_prefix, char *out_hex)
{
for(int i =0;i<16;++i) {
sprintf(out_hex + i*2, "%02x", (int)*(iv_prefix + i));
for (int i = 0; i < 16; ++i)
{
sprintf(out_hex + i * 2, "%02x", (int) *(iv_prefix + i));
}
out_hex[32] = 0;
}
#endif
static void
SetIVPrefix(ItemPointerData* ip, char* iv_prefix)
SetIVPrefix(ItemPointerData *ip, char *iv_prefix)
{
/* We have up to 16 bytes for the entire IV
* The higher bytes (starting with 15) are used for the incrementing counter
* The lower bytes (in this case, 0..5) are used for the tuple identification
* Tuple identification is based on CTID, which currently is 48 bytes in
* postgres: 4 bytes for the block id and 2 bytes for the position id
/*
* We have up to 16 bytes for the entire IV The higher bytes (starting
* with 15) are used for the incrementing counter The lower bytes (in this
* case, 0..5) are used for the tuple identification Tuple identification
* is based on CTID, which currently is 48 bytes in postgres: 4 bytes for
* the block id and 2 bytes for the position id
*/
iv_prefix[0] = ip->ip_blkid.bi_hi / 256;
iv_prefix[1] = ip->ip_blkid.bi_hi % 256;
@ -37,20 +40,20 @@ SetIVPrefix(ItemPointerData* ip, char* iv_prefix)
iv_prefix[5] = ip->ip_posid % 256;
}
/*
/*
* ================================================================
* ACTUAL ENCRYPTION/DECRYPTION FUNCTIONS
* ================================================================
*/
/*
/*
* pg_tde_crypt_simple:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file.
* 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, RelKeyData* key, const char* context)
pg_tde_crypt_simple(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, 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;
@ -63,38 +66,39 @@ pg_tde_crypt_simple(const char* iv_prefix, uint32 start_offset, const char* data
Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, aes_start_block, aes_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG
{
char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG,
(errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s",
context?context:"", start_offset, data_len, aes_start_block, aes_end_block, ivp_debug)));
}
{
char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG,
(errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s",
context ? context : "", start_offset, data_len, aes_start_block, aes_end_block, ivp_debug)));
}
#endif
for(uint32 i = 0; i < data_len; ++i)
for (uint32 i = 0; i < data_len; ++i)
{
out[i] = data[i] ^ enc_key[i + aes_block_no];
}
}
/*
/*
* pg_tde_crypt_complex:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file.
* 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, RelKeyData* key, const char* context)
pg_tde_crypt_complex(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, 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;
const uint64 aes_end_block = (start_offset + data_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE;
const uint64 aes_block_no = start_offset % AES_BLOCK_SIZE;
uint32 batch_no = 0;
uint32 data_index = 0;
uint64 batch_end_block;
uint32 current_batch_bytes;
uint32 batch_no = 0;
uint32 data_index = 0;
uint64 batch_end_block;
uint32 current_batch_bytes;
unsigned char enc_key[DATA_BYTES_PER_AES_BATCH];
/* do max NUM_AES_BLOCKS_IN_BATCH blocks at a time */
@ -104,60 +108,64 @@ pg_tde_crypt_complex(const char* iv_prefix, uint32 start_offset, const char* dat
Aes128EncryptedZeroBlocks(&(key->internal_key.ctx), key->internal_key.key, iv_prefix, batch_start_block, batch_end_block, enc_key);
#ifdef ENCRYPTION_DEBUG
{
char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG,
(errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s",
context?context:"", batch_no, start_offset, data_len, batch_start_block, batch_end_block, ivp_debug)));
}
{
char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG,
(errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s",
context ? context : "", batch_no, start_offset, data_len, batch_start_block, batch_end_block, ivp_debug)));
}
#endif
current_batch_bytes = ((batch_end_block - batch_start_block) * AES_BLOCK_SIZE)
- (batch_no > 0 ? 0 : aes_block_no); /* first batch skips `aes_block_no`-th bytes of enc_key */
- (batch_no > 0 ? 0 : aes_block_no); /* first batch skips
* `aes_block_no`-th bytes
* of enc_key */
if ((data_index + current_batch_bytes) > data_len)
current_batch_bytes = data_len - data_index;
for(uint32 i = 0; i < current_batch_bytes; ++i)
for (uint32 i = 0; i < current_batch_bytes; ++i)
{
/*
* As the size of enc_key always is a multiple of 16 we
* start from `aes_block_no`-th index of the enc_key[]
* so N-th will be crypted with the same enc_key byte despite
* what start_offset the function was called with.
* For example start_offset = 10; MAX_AES_ENC_BATCH_KEY_SIZE = 6:
* data: [10 11 12 13 14 15 16]
* encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5]
* so the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc.
* We need this shift so each byte will be coded the same despite
* the initial offset.
* Let's see the same data but sent to the func starting from the offset 0:
* data: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
* encKey: [0 1 2 3 4 5][0 1 2 3 4 5][ 0 1 2 3 4 5]
* again, the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc.
/*
* As the size of enc_key always is a multiple of 16 we start from
* `aes_block_no`-th index of the enc_key[] so N-th will be
* crypted with the same enc_key byte despite what start_offset
* the function was called with. For example start_offset = 10;
* MAX_AES_ENC_BATCH_KEY_SIZE = 6: data: [10 11 12
* 13 14 15 16] encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5] so
* the 10th data byte is encoded with the 4th byte of the 2nd
* enc_key etc. We need this shift so each byte will be coded the
* same despite the initial offset. Let's see the same data but
* sent to the func starting from the offset 0: data: [0 1 2 3
* 4 5 6 7 8 9 10 11 12 13 14 15 16] encKey: [0 1 2 3 4 5][0 1 2 3
* 4 5][ 0 1 2 3 4 5] again, the 10th data byte is encoded
* with the 4th byte of the 2nd enc_key etc.
*/
uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no);
uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no);
out[data_index] = data[data_index] ^ enc_key[enc_key_index];
data_index++;
}
batch_no++;
}
}
}
/*
/*
* pg_tde_crypt:
* Encrypts/decrypts `data` with a given `key`. The result is written to `out`.
* start_offset: is the absolute location of start of data in the file.
* 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, RelKeyData* key, const char* context)
pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context)
{
if(data_len >= DATA_BYTES_PER_AES_BATCH)
if (data_len >= DATA_BYTES_PER_AES_BATCH)
{
pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context);
} else
}
else
{
pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context);
}
@ -172,51 +180,52 @@ pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint3
* context: Optional context message to be used in debug log
* */
void
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData* key, const char* context)
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData *key, const char *context)
{
char iv_prefix[16] = {0};
uint32 data_len = tuple->t_len - tuple->t_data->t_hoff;
char *tup_data = (char*)tuple->t_data + tuple->t_data->t_hoff;
char *out_data = (char*)out_tuple->t_data + out_tuple->t_data->t_hoff;
char *tup_data = (char *) tuple->t_data + tuple->t_data->t_hoff;
char *out_data = (char *) out_tuple->t_data + out_tuple->t_data->t_hoff;
SetIVPrefix(&tuple->t_self, iv_prefix);
#ifdef ENCRYPTION_DEBUG
ereport(LOG,
(errmsg("%s: table Oid: %u data size: %u",
context?context:"", tuple->t_tableOid,
data_len)));
ereport(LOG,
(errmsg("%s: table Oid: %u data size: %u",
context ? context : "", tuple->t_tableOid,
data_len)));
#endif
pg_tde_crypt(iv_prefix, 0, tup_data, data_len, out_data, key, context);
pg_tde_crypt(iv_prefix, 0, tup_data, data_len, out_data, key, context);
}
// ================================================================
// HELPER FUNCTIONS FOR ENCRYPTION
// ================================================================
/* ================================================================ */
/* HELPER FUNCTIONS FOR ENCRYPTION */
/* ================================================================ */
OffsetNumber
PGTdePageAddItemExtended(RelFileLocator rel,
Oid oid,
BlockNumber bn,
Page page,
Item item,
Size size,
OffsetNumber offsetNumber,
int flags)
Oid oid,
BlockNumber bn,
Page page,
Item item,
Size size,
OffsetNumber offsetNumber,
int flags)
{
OffsetNumber off = PageAddItemExtended(page,item,size,offsetNumber,flags);
PageHeader phdr = (PageHeader) page;
unsigned long header_size = ((HeapTupleHeader)item)->t_hoff;
OffsetNumber off = PageAddItemExtended(page, item, size, offsetNumber, flags);
PageHeader phdr = (PageHeader) page;
unsigned long header_size = ((HeapTupleHeader) item)->t_hoff;
char iv_prefix[16] = {0,};
char* toAddr = ((char*)phdr) + phdr->pd_upper + header_size;
char* data = item + header_size;
uint32 data_len = size - header_size;
char *toAddr = ((char *) phdr) + phdr->pd_upper + header_size;
char *data = item + header_size;
uint32 data_len = size - header_size;
/* ctid stored in item is incorrect (not set) at this point */
ItemPointerData ip;
RelKeyData *key = GetHeapBaiscRelationKey(rel);
ItemPointerSet(&ip, bn, off);
ItemPointerSet(&ip, bn, off);
SetIVPrefix(&ip, iv_prefix);
@ -234,21 +243,21 @@ PGTdePageAddItemExtended(RelFileLocator rel,
void
AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes)
{
unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* Ensure we are getting a valid pointer here */
Assert(principal_key);
memcpy(iv, &rlocator->spcOid, sizeof(Oid));
memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid));
*p_enc_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData));
memcpy(*p_enc_rel_key_data, rel_key_data, sizeof(RelKeyData));
AesEncrypt(principal_key->keyData, iv, ((unsigned char*)&rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_enc_rel_key_data)->internal_key), (int *)enc_key_bytes);
AesEncrypt(principal_key->keyData, iv, ((unsigned char *) &rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *) &(*p_enc_rel_key_data)->internal_key), (int *) enc_key_bytes);
}
#endif /* FRONTEND */
#endif /* FRONTEND */
/*
* Provide a simple interface to decrypt a given key.
@ -257,31 +266,32 @@ AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocat
* to note that memory is allocated in the TopMemoryContext so we expect this to be added
* to our key cache.
*/
void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes)
void
AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes)
{
unsigned char iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* Ensure we are getting a valid pointer here */
Assert(principal_key);
memcpy(iv, &rlocator->spcOid, sizeof(Oid));
memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid));
#ifndef FRONTEND
MemoryContext oldcontext;
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif
*p_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData));
#ifndef FRONTEND
MemoryContextSwitchTo(oldcontext);
MemoryContextSwitchTo(oldcontext);
#endif
/* Fill in the structure */
memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData));
(*p_rel_key_data)->internal_key.ctx = NULL;
AesDecrypt(principal_key->keyData, iv, ((unsigned char*) &enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_rel_key_data)->internal_key) , (int *)key_bytes);
}
AesDecrypt(principal_key->keyData, iv, ((unsigned char *) &enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *) &(*p_rel_key_data)->internal_key), (int *) key_bytes);
}

@ -14,4 +14,4 @@
extern void SetupTdeDDLHooks(void);
#endif /* PG_TDE_DDL_H */
#endif /* PG_TDE_DDL_H */

@ -29,8 +29,8 @@ typedef struct TDEBufferHeapTupleTableSlot
* reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set in
* such a case, since presumably base.tuple is pointing into the buffer.)
*/
Buffer buffer; /* tuple's buffer, or InvalidBuffer */
char decrypted_buffer[BLCKSZ];
Buffer buffer; /* tuple's buffer, or InvalidBuffer */
char decrypted_buffer[BLCKSZ];
RelKeyData *cached_relation_key;
} TDEBufferHeapTupleTableSlot;
@ -39,12 +39,12 @@ extern PGDLLIMPORT const TupleTableSlotOps TTSOpsTDEBufferHeapTuple;
#define TTS_IS_TDE_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsTDEBufferHeapTuple)
extern TupleTableSlot *PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer);
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer);
extern TupleTableSlot *PGTdeExecStoreBufferHeapTuple(Relation rel,
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer);
HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer);
#endif /* PG_TDE_SLOT_H */
#endif /* PG_TDE_SLOT_H */

@ -18,7 +18,7 @@
#define MAP_ENTRY_EMPTY 0x00
#define TDE_KEY_TYPE_HEAP_BASIC 0x01
#define TDE_KEY_TYPE_SMGR 0x02
#define TDE_KEY_TYPE_GLOBAL 0x04
#define TDE_KEY_TYPE_GLOBAL 0x04
#define MAP_ENTRY_VALID (TDE_KEY_TYPE_HEAP_BASIC | TDE_KEY_TYPE_SMGR | TDE_KEY_TYPE_GLOBAL)
typedef struct InternalKey
@ -37,8 +37,8 @@ typedef struct InternalKey
typedef struct RelKeyData
{
TDEPrincipalKeyId principal_key_id;
InternalKey internal_key;
TDEPrincipalKeyId principal_key_id;
InternalKey internal_key;
} RelKeyData;
@ -76,8 +76,8 @@ extern bool pg_tde_move_rel_key(const RelFileLocator *newrlocator, const RelFile
extern void pg_tde_set_db_file_paths(Oid dbOid, Oid spcOid, char *map_path, char *keydata_path);
const char * tde_sprint_key(InternalKey *k);
const char *tde_sprint_key(InternalKey *k);
extern RelKeyData *pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key);
#endif /*PG_TDE_MAP_H*/
#endif /* PG_TDE_MAP_H */

@ -38,5 +38,5 @@ static const RmgrData tdeheap_rmgr = {
.rm_identify = tdeheap_rmgr_identify
};
#endif /* !FRONTEND */
#endif /* PG_TDE_XLOG_H */
#endif /* !FRONTEND */
#endif /* PG_TDE_XLOG_H */

@ -30,6 +30,6 @@ static const XLogSmgr tde_xlog_smgr = {
extern void TDEXLogSmgrInit(void);
extern void XLogInitGUC(void);
#endif /* PERCONA_EXT */
#endif /* PERCONA_EXT */
#endif /* PG_TDE_XLOGENCRYPT_H */
#endif /* PG_TDE_XLOGENCRYPT_H */

@ -24,6 +24,6 @@
TDEInitGlobalKeys(kring_dir); \
TDEXLogSmgrInit()
#endif /* PERCONA_EXT */
#endif /* PERCONA_EXT */
#endif /* PG_TDE_XLOGENCRYPT_FE_H */
#endif /* PG_TDE_XLOGENCRYPT_FE_H */

@ -34,4 +34,4 @@
extern void TDEInitGlobalKeys(const char *dir);
#endif /* TDE_GLOBAL_CATALOG_H */
#endif /* TDE_GLOBAL_CATALOG_H */

@ -22,34 +22,35 @@
#define FILE_KEYRING_TYPE "file"
#define VAULTV2_KEYRING_TYPE "vault-v2"
#define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name size*/
#define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */
#define MAX_KEYRING_OPTION_LEN 1024
#define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name
* size */
#define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */
#define MAX_KEYRING_OPTION_LEN 1024
typedef enum ProviderType
{
UNKNOWN_KEY_PROVIDER,
FILE_KEY_PROVIDER,
VAULT_V2_KEY_PROVIDER,
} ProviderType;
} ProviderType;
/* Base type for all keyring */
typedef struct GenericKeyring
{
ProviderType type; /* Must be the first field */
Oid key_id;
ProviderType type; /* Must be the first field */
Oid key_id;
char provider_name[MAX_PROVIDER_NAME_LEN];
char options[MAX_KEYRING_OPTION_LEN]; /* User provided options string*/
char options[MAX_KEYRING_OPTION_LEN]; /* User provided options string */
} GenericKeyring;
typedef struct FileKeyring
{
GenericKeyring keyring; /* Must be the first field */
GenericKeyring keyring; /* Must be the first field */
char file_name[MAXPGPATH];
} FileKeyring;
typedef struct VaultV2Keyring
{
GenericKeyring keyring; /* Must be the first field */
GenericKeyring keyring; /* Must be the first field */
char vault_token[MAX_VAULT_V2_KEY_LEN];
char vault_url[MAXPGPATH];
char vault_ca_path[MAXPGPATH];
@ -59,15 +60,15 @@ typedef struct VaultV2Keyring
/* This record goes into key provider info file */
typedef struct KeyringProvideRecord
{
int provider_id;
int provider_id;
char provider_name[MAX_PROVIDER_NAME_LEN];
char options[MAX_KEYRING_OPTION_LEN];
ProviderType provider_type;
} KeyringProvideRecord;
typedef struct KeyringProviderXLRecord
{
Oid database_id;
Oid tablespace_id;
Oid database_id;
Oid tablespace_id;
off_t offset_in_file;
KeyringProvideRecord provider;
} KeyringProviderXLRecord;
@ -87,5 +88,5 @@ extern uint32 copy_key_provider_info(KeyringProvideRecord* provider,
extern uint32 redo_key_provider_info(KeyringProviderXLRecord *xlrec);
extern bool ParseKeyringJSONOptions(ProviderType provider_type, void *out_opts,
char *in_buf, int buf_len);
#endif /*TDE_KEYRING_H*/
char *in_buf, int buf_len);
#endif /* TDE_KEYRING_H */

@ -19,23 +19,23 @@
#include "storage/lwlock.h"
#endif
#define DEFAULT_PRINCIPAL_KEY_VERSION 1
#define DEFAULT_PRINCIPAL_KEY_VERSION 1
#define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN
#define MAX_PRINCIPAL_KEY_VERSION_NUM 100000
typedef struct TDEPrincipalKeyId
{
uint32 version;
char name[PRINCIPAL_KEY_NAME_LEN];
char versioned_name[PRINCIPAL_KEY_NAME_LEN + 4];
uint32 version;
char name[PRINCIPAL_KEY_NAME_LEN];
char versioned_name[PRINCIPAL_KEY_NAME_LEN + 4];
} TDEPrincipalKeyId;
typedef struct TDEPrincipalKeyInfo
{
Oid databaseId;
Oid tablespaceId;
Oid userId;
Oid keyringId;
Oid databaseId;
Oid tablespaceId;
Oid userId;
Oid keyringId;
struct timeval creationTime;
TDEPrincipalKeyId keyId;
} TDEPrincipalKeyInfo;
@ -52,7 +52,7 @@ typedef struct XLogPrincipalKeyRotate
Oid databaseId;
off_t map_size;
off_t keydata_size;
char buff[FLEXIBLE_ARRAY_MEMBER];
char buff[FLEXIBLE_ARRAY_MEMBER];
} XLogPrincipalKeyRotate;
#define SizeoOfXLogPrincipalKeyRotate offsetof(XLogPrincipalKeyRotate, buff)
@ -62,16 +62,16 @@ extern void cleanup_principal_key_info(Oid databaseId, Oid tablespaceId);
#ifndef FRONTEND
extern LWLock *tde_lwlock_enc_keys(void);
extern TDEPrincipalKey* GetPrincipalKey(Oid dbOid, Oid spcOid, LWLockMode lockMode);
extern TDEPrincipalKey *GetPrincipalKey(Oid dbOid, Oid spcOid, LWLockMode lockMode);
#else
extern TDEPrincipalKey* GetPrincipalKey(Oid dbOid, Oid spcOid, void *lockMode);
extern TDEPrincipalKey *GetPrincipalKey(Oid dbOid, Oid spcOid, void *lockMode);
#endif
extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo);
extern Oid GetPrincipalKeyProviderId(void);
extern Oid GetPrincipalKeyProviderId(void);
extern bool SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new_key);
extern bool RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const char *new_provider_name, bool ensure_new_key);
extern bool xl_tde_perform_rotate_key(XLogPrincipalKeyRotate *xlrec);
#endif /*PG_TDE_PRINCIPAL_KEY_H*/
#endif /* PG_TDE_PRINCIPAL_KEY_H */

@ -18,43 +18,46 @@
typedef enum
{
TDE_LWLOCK_ENC_KEY,
TDE_LWLOCK_PI_FILES,
TDE_LWLOCK_ENC_KEY,
TDE_LWLOCK_PI_FILES,
/* Must be the last entry in the enum */
TDE_LWLOCK_COUNT
/* Must be the last entry in the enum */
TDE_LWLOCK_COUNT
} TDELockTypes;
typedef struct TDEShmemSetupRoutine
{
/* init_shared_state gets called at the time of extension load
* you can initialize the data structures required to be placed in
* shared memory in this callback
* The callback must return the size of the shared memory area acquired.
* The argument to the function is the start of the shared memory address
* that can be used to store the shared data structures.
*/
Size (*init_shared_state)(void *raw_dsa_area);
/*
* shmem_startup gets called at the time of postmaster shutdown
*/
void (*shmem_kill)(int code, Datum arg);
/*
* The callback must return the size of the shared memory acquired.
*/
Size (*required_shared_mem_size)(void);
/*
* Gets called after all shared memory structures are initialized and
* here you can create shared memory hash tables or any other shared
* objects that needs to live in DSA area.
*/
void (*init_dsa_area_objects)(dsa_area *dsa, void *raw_dsa_area);
/*
* init_shared_state gets called at the time of extension load you can
* initialize the data structures required to be placed in shared memory
* in this callback The callback must return the size of the shared memory
* area acquired. The argument to the function is the start of the shared
* memory address that can be used to store the shared data structures.
*/
Size (*init_shared_state) (void *raw_dsa_area);
/*
* shmem_startup gets called at the time of postmaster shutdown
*/
void (*shmem_kill) (int code, Datum arg);
/*
* The callback must return the size of the shared memory acquired.
*/
Size (*required_shared_mem_size) (void);
/*
* Gets called after all shared memory structures are initialized and here
* you can create shared memory hash tables or any other shared objects
* that needs to live in DSA area.
*/
void (*init_dsa_area_objects) (dsa_area *dsa, void *raw_dsa_area);
} TDEShmemSetupRoutine;
/* Interface to register the shared memory requests */
extern void RegisterShmemRequest(const TDEShmemSetupRoutine *routine);
extern void TdeShmemInit(void);
extern Size TdeRequiredSharedMemorySize(void);
extern int TdeRequiredLocksCount(void);
extern int TdeRequiredLocksCount(void);
#endif /*PG_TDE_SHMEM_H*/
#endif /* PG_TDE_SHMEM_H */

@ -13,12 +13,12 @@
#ifndef FRONTEND
#include "nodes/pg_list.h"
extern Oid get_tde_basic_table_am_oid(void);
extern Oid get_tde_table_am_oid(void);
extern Oid get_tde_basic_table_am_oid(void);
extern Oid get_tde_table_am_oid(void);
extern List *get_all_tde_tables(void);
extern int get_tde_tables_count(void);
extern int get_tde_tables_count(void);
#endif /* !FRONTEND */
extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid);
extern void pg_tde_set_globalspace_dir(const char *dir);
#endif /*PG_TDE_UTILS_H*/
#endif /* PG_TDE_UTILS_H */

@ -17,10 +17,10 @@
#define DATA_BYTES_PER_AES_BATCH (NUM_AES_BLOCKS_IN_BATCH * AES_BLOCK_SIZE)
void AesInit(void);
extern void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const char* iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char* out);
extern void Aes128EncryptedZeroBlocks(void *ctxPtr, const unsigned char *key, const char *iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char *out);
/* Only used for testing */
extern void AesEncrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len);
extern void AesDecrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len);
extern void AesEncrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len);
extern void AesDecrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len);
#endif /*ENC_AES_H*/
#endif /* ENC_AES_H */

@ -18,17 +18,17 @@
#include "keyring/keyring_api.h"
extern void
pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint32 data_len, char* out, RelKeyData* key, const char* context);
pg_tde_crypt(const char *iv_prefix, uint32 start_offset, const char *data, uint32 data_len, char *out, RelKeyData *key, const char *context);
extern void
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData* key, const char* context);
pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData *key, const char *context);
/* A wrapper to encrypt a tuple before adding it to the buffer */
extern OffsetNumber
PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page,
Item item,
Size size,
OffsetNumber offsetNumber,
int flags);
PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page,
Item item,
Size size,
OffsetNumber offsetNumber,
int flags);
/* Function Macros over crypt */
@ -55,4 +55,4 @@ PGTdePageAddItemExtended(RelFileLocator rel, Oid oid, BlockNumber bn, Page page,
extern void AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData *rel_key_data, RelKeyData **p_enc_rel_key_data, size_t *enc_key_bytes);
extern void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes);
#endif /*ENC_TDE_H*/
#endif /* ENC_TDE_H */

@ -12,7 +12,7 @@
#include "catalog/tde_keyring.h"
#define TDE_KEY_NAME_LEN 256
#define MAX_KEY_DATA_SIZE 32 /* maximum 256 bit encryption */
#define MAX_KEY_DATA_SIZE 32 /* maximum 256 bit encryption */
#define INTERNAL_KEY_LEN 16
typedef struct keyName
@ -28,8 +28,8 @@ typedef struct keyData
typedef struct keyInfo
{
keyName name;
keyData data;
keyName name;
keyData data;
} keyInfo;
typedef enum KeyringReturnCodes
@ -46,14 +46,14 @@ typedef enum KeyringReturnCodes
typedef struct TDEKeyringRoutine
{
keyInfo *(*keyring_get_key)(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode);
KeyringReturnCodes (*keyring_store_key)(GenericKeyring *keyring, keyInfo *key, bool throw_error);
keyInfo *(*keyring_get_key) (GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode);
KeyringReturnCodes(*keyring_store_key) (GenericKeyring *keyring, keyInfo *key, bool throw_error);
} TDEKeyringRoutine;
extern bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type);
extern KeyringReturnCodes KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error);
extern keyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode);
extern keyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode);
extern keyInfo *KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error);
extern keyInfo *KeyringGenerateNewKey(const char *key_name, unsigned key_len);

@ -19,13 +19,14 @@
#include <stdbool.h>
#include <curl/curl.h>
typedef struct CurlString {
char *ptr;
size_t len;
typedef struct CurlString
{
char *ptr;
size_t len;
} CurlString;
extern CURL* keyringCurl;
extern CURL * keyringCurl;
bool curlSetupSession(const char* url, const char* caFile, CurlString* outStr);
bool curlSetupSession(const char *url, const char *caFile, CurlString *outStr);
#endif //KEYRING_CURL_H
#endif /* //KEYRING_CURL_H */

@ -14,4 +14,4 @@
extern bool InstallFileKeyring(void);
#endif /*KEYRING_FILE_H*/
#endif /* KEYRING_FILE_H */

@ -14,4 +14,4 @@
extern bool InstallVaultV2Keyring(void);
#endif // KEYRING_FILE_H
#endif /* KEYRING_FILE_H */

@ -10,13 +10,13 @@
typedef struct XLogExtensionInstall
{
Oid database_id;
Oid tablespace_id;
Oid database_id;
Oid tablespace_id;
} XLogExtensionInstall;
typedef void (*pg_tde_on_ext_install_callback)(int tde_tbl_count, XLogExtensionInstall* ext_info, bool redo, void *arg);
typedef void (*pg_tde_on_ext_install_callback) (int tde_tbl_count, XLogExtensionInstall *ext_info, bool redo, void *arg);
extern void on_ext_install(pg_tde_on_ext_install_callback function, void* arg);
extern void on_ext_install(pg_tde_on_ext_install_callback function, void *arg);
extern void extension_install_redo(XLogExtensionInstall *xlrec);
#endif /*PG_TDE_H*/
#endif /* PG_TDE_H */

@ -19,10 +19,10 @@
* ----------
*/
//#define ENCRYPTION_DEBUG 1
//#define KEYRING_DEBUG 1
//#define TDE_FORK_DEBUG 1
// #define TDE_XLOG_DEBUG 1
/* #define ENCRYPTION_DEBUG 1 */
/* #define KEYRING_DEBUG 1 */
/* #define TDE_FORK_DEBUG 1 */
/* #define TDE_XLOG_DEBUG 1 */
#define tdeheap_fill_tuple heap_fill_tuple
#define tdeheap_form_tuple heap_form_tuple
@ -47,4 +47,4 @@
/* ---------- */
#endif /* PG_TDE_DEFINES_H */
#endif /* PG_TDE_DEFINES_H */

@ -13,4 +13,4 @@ extern const char *pg_tde_package_string(void);
extern const char *pg_tde_package_name(void);
extern const char *pg_tde_package_version(void);
#endif /*PG_TDE_DEFS_H*/
#endif /* PG_TDE_DEFS_H */

@ -15,19 +15,19 @@ typedef enum TdeCreateEventType
TDE_UNKNOWN_CREATE_EVENT,
TDE_TABLE_CREATE_EVENT,
TDE_INDEX_CREATE_EVENT
} TdeCreateEventType;
} TdeCreateEventType;
typedef struct TdeCreateEvent
{
TdeCreateEventType eventType; /* DDL statement type */
bool encryptMode; /* true when the table uses encryption */
Oid baseTableOid; /* Oid of table on which index is being
bool encryptMode; /* true when the table uses encryption */
Oid baseTableOid; /* Oid of table on which index is being
* created on. For create table statement this
* contains InvalidOid */
RangeVar *relation; /* Reference to the parsed relation from
RangeVar *relation; /* Reference to the parsed relation from
* create statement */
} TdeCreateEvent;
} TdeCreateEvent;
extern TdeCreateEvent * GetCurrentTdeCreateEvent(void);
extern TdeCreateEvent *GetCurrentTdeCreateEvent(void);
#endif

@ -12,4 +12,4 @@
extern void RegisterStorageMgr(void);
#endif /* PG_TDE_SMGR_H */
#endif /* PG_TDE_SMGR_H */

@ -13,9 +13,9 @@
extern void pg_tde_xact_callback(XactEvent event, void *arg);
extern void pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg);
SubTransactionId parentSubid, void *arg);
extern void RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit);
#endif /* PG_TDE_XACT_HANDLER_H */
#endif /* PG_TDE_XACT_HANDLER_H */

@ -34,9 +34,11 @@ static KeyProviders *
find_key_provider(ProviderType type)
{
ListCell *lc;
foreach (lc, registeredKeyProviders)
foreach(lc, registeredKeyProviders)
{
KeyProviders *kp = (KeyProviders *)lfirst(lc);
KeyProviders *kp = (KeyProviders *) lfirst(lc);
if (kp->type == type)
{
return kp;
@ -49,9 +51,11 @@ static KeyProviders *
find_key_provider(ProviderType type)
{
SimplePtrListCell *lc;
for (lc = registeredKeyProviders.head; lc; lc = lc->next)
{
KeyProviders *kp = (KeyProviders *) lc->ptr;
if (kp->type == type)
{
return kp;
@ -59,9 +63,10 @@ find_key_provider(ProviderType type)
}
return NULL;
}
#endif /* !FRONTEND */
#endif /* !FRONTEND */
bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
bool
RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
{
KeyProviders *kp;
@ -79,10 +84,11 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
#ifndef FRONTEND
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif
kp = palloc(sizeof(KeyProviders));
kp->routine = (TDEKeyringRoutine *)routine;
kp->routine = (TDEKeyringRoutine *) routine;
kp->type = type;
#ifndef FRONTEND
registeredKeyProviders = lappend(registeredKeyProviders, kp);
@ -95,9 +101,10 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
}
keyInfo *
KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *returnCode)
KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode)
{
KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL)
{
ereport(throw_error ? ERROR : WARNING,
@ -112,6 +119,7 @@ KeyringReturnCodes
KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{
KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL)
{
ereport(throw_error ? ERROR : WARNING,
@ -125,13 +133,14 @@ keyInfo *
KeyringGenerateNewKey(const char *key_name, unsigned key_len)
{
keyInfo *key;
Assert(key_len <= 32);
key = palloc(sizeof(keyInfo));
key->data.len = key_len;
if (!RAND_bytes(key->data.data, key_len))
{
pfree(key);
return NULL; /*openssl error*/
return NULL; /* openssl error */
}
strncpy(key->name.name, key_name, sizeof(key->name.name));
return key;
@ -141,6 +150,7 @@ keyInfo *
KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error)
{
keyInfo *key = KeyringGenerateNewKey(key_name, key_len);
if (key == NULL)
{
ereport(throw_error ? ERROR : WARNING,

@ -14,50 +14,69 @@
#include "keyring/keyring_curl.h"
#include "pg_tde_defines.h"
CURL* keyringCurl = NULL;
CURL *keyringCurl = NULL;
static
size_t write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s)
size_t
write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s)
{
size_t new_len = s->len + size*nmemb;
s->ptr = repalloc(s->ptr, new_len+1);
if (s->ptr == NULL) {
size_t new_len = s->len + size * nmemb;
s->ptr = repalloc(s->ptr, new_len + 1);
if (s->ptr == NULL)
{
exit(EXIT_FAILURE);
}
memcpy(s->ptr+s->len, ptr, size*nmemb);
memcpy(s->ptr + s->len, ptr, size * nmemb);
s->ptr[new_len] = '\0';
s->len = new_len;
return size*nmemb;
return size * nmemb;
}
bool curlSetupSession(const char* url, const char* caFile, CurlString* outStr)
bool
curlSetupSession(const char *url, const char *caFile, CurlString *outStr)
{
if(keyringCurl == NULL)
if (keyringCurl == NULL)
{
keyringCurl = curl_easy_init();
if(keyringCurl == NULL) return 0;
} else {
curl_easy_reset(keyringCurl);
}
if (keyringCurl == NULL)
return 0;
}
else
{
curl_easy_reset(keyringCurl);
}
if(curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) return 0;
if(caFile != NULL && strlen(caFile) != 0)
if (curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK)
return 0;
if (caFile != NULL && strlen(caFile) != 0)
{
if(curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK) return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK)
return 0;
}
if(curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION,(long)CURL_HTTP_VERSION_1_1) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION,write_func) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA,outStr) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK) return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_1_1) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION, write_func) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA, outStr) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK)
return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK) return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK) return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK)
return 0;
return 1;
}
}

@ -26,8 +26,8 @@
#include <stdio.h>
#include <unistd.h>
static keyInfo* get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error, KeyringReturnCodes *return_code);
static KeyringReturnCodes set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error);
static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code);
static KeyringReturnCodes set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error);
const TDEKeyringRoutine keyringFileRoutine = {
.keyring_get_key = get_key_by_name,
@ -41,12 +41,12 @@ InstallFileKeyring(void)
}
static keyInfo*
get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error, KeyringReturnCodes *return_code)
static keyInfo *
get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code)
{
keyInfo* key = NULL;
keyInfo *key = NULL;
int fd = -1;
FileKeyring* file_keyring = (FileKeyring*)keyring;
FileKeyring *file_keyring = (FileKeyring *) keyring;
off_t bytes_read = 0;
off_t curr_pos = 0;
@ -57,15 +57,16 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
return NULL;
key = palloc(sizeof(keyInfo));
while(true)
while (true)
{
bytes_read = pg_pread(fd, key, sizeof(keyInfo), curr_pos);
curr_pos += bytes_read;
if (bytes_read == 0 )
if (bytes_read == 0)
{
/*
* Empty keyring file is considered as a valid keyring file that has no keys
* Empty keyring file is considered as a valid keyring file that
* has no keys
*/
close(fd);
pfree(key);
@ -77,11 +78,11 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
pfree(key);
/* Corrupt file */
*return_code = KEYRING_CODE_DATA_CORRUPTED;
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
errmsg("keyring file \"%s\" is corrupted: %m",
file_keyring->file_name),
errdetail("invalid key size %llu expected %lu", bytes_read, sizeof(keyInfo))));
ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(),
errmsg("keyring file \"%s\" is corrupted: %m",
file_keyring->file_name),
errdetail("invalid key size %llu expected %lu", bytes_read, sizeof(keyInfo))));
return NULL;
}
if (strncasecmp(key->name.name, key_name, sizeof(key->name.name)) == 0)
@ -96,13 +97,13 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
}
static KeyringReturnCodes
set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{
off_t bytes_written = 0;
off_t curr_pos = 0;
int fd;
FileKeyring* file_keyring = (FileKeyring*)keyring;
keyInfo *existing_key;
int fd;
FileKeyring *file_keyring = (FileKeyring *) keyring;
keyInfo *existing_key;
KeyringReturnCodes return_code = KEYRING_CODE_SUCCESS;
Assert(key != NULL);
@ -119,9 +120,9 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
fd = BasicOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY);
if (fd < 0)
{
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
errmsg("Failed to open keyring file %s :%m", file_keyring->file_name)));
ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(),
errmsg("Failed to open keyring file %s :%m", file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
/* Write key to the end of file */
@ -130,20 +131,20 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
if (bytes_written != sizeof(keyInfo))
{
close(fd);
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
errmsg("keyring file \"%s\" can't be written: %m",
file_keyring->file_name)));
ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(),
errmsg("keyring file \"%s\" can't be written: %m",
file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
if (pg_fsync(fd) != 0)
{
close(fd);
ereport(throw_error?ERROR:WARNING,
ereport(throw_error ? ERROR : WARNING,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m",
file_keyring->file_name)));
file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
close(fd);

@ -18,7 +18,7 @@
#include "common/jsonapi.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include <stdio.h>
#include <curl/curl.h>
@ -49,18 +49,18 @@ typedef enum
typedef struct JsonVaultRespState
{
JsonVaultRespSemState state;
JsonVaultRespField field;
int level;
char *key;
JsonVaultRespSemState state;
JsonVaultRespField field;
int level;
char *key;
} JsonVaultRespState;
static JsonParseErrorType json_resp_object_start(void *state);
static JsonParseErrorType json_resp_object_end(void *state);
static JsonParseErrorType json_resp_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType json_resp_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex);
static JsonParseErrorType parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex);
struct curl_slist *curlList = NULL;
@ -69,7 +69,7 @@ static char *get_keyring_vault_url(VaultV2Keyring *keyring, const char *key_name
static bool curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData);
static KeyringReturnCodes set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error);
static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *return_code);
static keyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code);
const TDEKeyringRoutine keyringVaultV2Routine = {
.keyring_get_key = get_key_by_name,
@ -77,7 +77,8 @@ const TDEKeyringRoutine keyringVaultV2Routine = {
};
bool InstallVaultV2Keyring(void)
bool
InstallVaultV2Keyring(void)
{
return RegisterKeyProvider(&keyringVaultV2Routine, VAULT_V2_KEY_PROVIDER);
}
@ -85,20 +86,24 @@ bool InstallVaultV2Keyring(void)
static bool
curl_setup_token(VaultV2Keyring *keyring)
{
if(curlList == NULL)
if (curlList == NULL)
{
char tokenHeader[256];
strcpy(tokenHeader, "X-Vault-Token:");
strcat(tokenHeader, keyring->vault_token);
curlList = curl_slist_append(curlList, tokenHeader);
if(curlList == NULL) return 0;
if (curlList == NULL)
return 0;
curlList = curl_slist_append(curlList, "Content-Type: application/json");
if(curlList == NULL) return 0;
if (curlList == NULL)
return 0;
}
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK) return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK)
return 0;
return 1;
}
@ -106,10 +111,10 @@ curl_setup_token(VaultV2Keyring *keyring)
static bool
curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long *httpCode, const char *postData)
{
CURLcode ret;
CURLcode ret;
#if KEYRING_DEBUG
elog(DEBUG1, "Performing Vault HTTP [%s] request to '%s'", postData != NULL ? "POST" : "GET", url);
if(postData != NULL)
if (postData != NULL)
{
elog(DEBUG2, "Postdata: '%s'", postData);
}
@ -123,9 +128,10 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
if (!curl_setup_token(keyring))
return 0;
if(postData != NULL)
if (postData != NULL)
{
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK) return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK)
return 0;
}
ret = curl_easy_perform(keyringCurl);
@ -135,7 +141,8 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
return 0;
}
if(curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK) return 0;
if (curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK)
return 0;
#if KEYRING_DEBUG
elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : "");
@ -160,23 +167,26 @@ get_keyring_vault_url(VaultV2Keyring *keyring, const char *key_name, char *out,
}
static KeyringReturnCodes
set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
set_key_by_name(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{
VaultV2Keyring *vault_keyring = (VaultV2Keyring *)keyring;
VaultV2Keyring *vault_keyring = (VaultV2Keyring *) keyring;
char url[VAULT_URL_MAX_LEN];
CurlString str;
long httpCode = 0;
char jsonText[512];
char keyData[64];
int keyLen = 0;
int keyLen = 0;
Assert(key != NULL);
// Since we are only building a very limited JSON with a single base64 string, we build it by hand
// Simpler than using the limited pg json api
keyLen = pg_b64_encode((char *)key->data.data, key->data.len, keyData, 64);
/*
* Since we are only building a very limited JSON with a single base64
* string, we build it by hand
*/
/* Simpler than using the limited pg json api */
keyLen = pg_b64_encode((char *) key->data.data, key->data.len, keyData, 64);
keyData[keyLen] = 0;
snprintf(jsonText, 512, "{\"data\":{\"key\":\"%s\"}}", keyData);
#if KEYRING_DEBUG
@ -207,18 +217,18 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
}
static keyInfo *
get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes *return_code)
get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * return_code)
{
VaultV2Keyring *vault_keyring = (VaultV2Keyring *)keyring;
keyInfo* key = NULL;
VaultV2Keyring *vault_keyring = (VaultV2Keyring *) keyring;
keyInfo *key = NULL;
char url[VAULT_URL_MAX_LEN];
CurlString str;
long httpCode = 0;
JsonParseErrorType json_error;
JsonLexContext *jlex = NULL;
JsonVaultRespState parse;
JsonParseErrorType json_error;
JsonLexContext *jlex = NULL;
JsonVaultRespState parse;
const char* responseKey;
const char *responseKey;
*return_code = KEYRING_CODE_SUCCESS;
@ -271,7 +281,7 @@ get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error,
#endif
key = palloc(sizeof(keyInfo));
key->data.len = pg_b64_decode(responseKey, strlen(responseKey), (char *)key->data.data, MAX_KEY_DATA_SIZE);
key->data.len = pg_b64_decode(responseKey, strlen(responseKey), (char *) key->data.data, MAX_KEY_DATA_SIZE);
if (key->data.len > MAX_KEY_DATA_SIZE)
{
@ -285,7 +295,7 @@ get_key_by_name(GenericKeyring *keyring, const char *key_name, bool throw_error,
}
cleanup:
if(str.ptr != NULL)
if (str.ptr != NULL)
pfree(str.ptr);
#if PG_VERSION_NUM >= 170000
if (jlex != NULL)
@ -296,7 +306,7 @@ cleanup:
/*
* JSON parser routines
*
*
* We expect the response in the form of:
* {
* ...
@ -307,14 +317,14 @@ cleanup:
* }
* ...
* }
*
*
* the rest fields are ignored
*/
static JsonParseErrorType
parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex)
parse_json_response(JsonVaultRespState *parse, JsonLexContext *lex)
{
JsonSemAction sem;
JsonSemAction sem;
parse->state = JRESP_EXPECT_TOP_DATA;
parse->level = -1;
@ -408,6 +418,6 @@ json_resp_object_field_start(void *state, char *fname, bool isnull)
parse->field = JRESP_F_KEY;
break;
}
return JSON_SUCCESS;
}

@ -45,11 +45,11 @@ PG_MODULE_MAGIC;
struct OnExtInstall
{
pg_tde_on_ext_install_callback function;
void* arg;
void *arg;
};
static struct OnExtInstall on_ext_install_list[MAX_ON_INSTALLS];
static int on_ext_install_index = 0;
static int on_ext_install_index = 0;
static void run_extension_install_callbacks(XLogExtensionInstall *xlrec, bool redo);
void _PG_init(void);
Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS);
@ -63,8 +63,8 @@ PG_FUNCTION_INFO_V1(pg_tde_version);
static void
tde_shmem_request(void)
{
Size sz = TdeRequiredSharedMemorySize();
int required_locks = TdeRequiredLocksCount();
Size sz = TdeRequiredSharedMemorySize();
int required_locks = TdeRequiredLocksCount();
#ifdef PERCONA_EXT
sz = add_size(sz, XLOG_TDE_ENC_BUFF_ALIGNED_SIZE);
@ -122,16 +122,22 @@ _PG_init(void)
RegisterStorageMgr();
}
Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS)
Datum
pg_tde_extension_initialize(PG_FUNCTION_ARGS)
{
/* Initialize the TDE map */
XLogExtensionInstall xlrec;
xlrec.database_id = MyDatabaseId;
xlrec.tablespace_id = MyDatabaseTableSpace;
run_extension_install_callbacks(&xlrec, false);
/* Also put this info in xlog, so we can replicate the same on the other side */
/*
* Also put this info in xlog, so we can replicate the same on the other
* side
*/
XLogBeginInsert();
XLogRegisterData((char *)&xlrec, sizeof(XLogExtensionInstall));
XLogRegisterData((char *) &xlrec, sizeof(XLogExtensionInstall));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_EXTENSION_INSTALL_KEY);
PG_RETURN_NULL();
@ -149,12 +155,13 @@ extension_install_redo(XLogExtensionInstall *xlrec)
* run at the time of pg_tde extension installs.
* ----------------------------------------------------------------
*/
void on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
void
on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
{
if (on_ext_install_index >= MAX_ON_INSTALLS)
ereport(FATAL,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg_internal("out of on extension install slots")));
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg_internal("out of on extension install slots")));
on_ext_install_list[on_ext_install_index].function = function;
on_ext_install_list[on_ext_install_index].arg = arg;
@ -167,14 +174,14 @@ void on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
* ------------------
*/
static void
run_extension_install_callbacks(XLogExtensionInstall* xlrec , bool redo)
run_extension_install_callbacks(XLogExtensionInstall *xlrec, bool redo)
{
int i;
int tde_table_count =0;
int i;
int tde_table_count = 0;
/*
* Get the number of tde tables in this database
* should always be zero. But still, it prevents
* the cleanup if someone explicitly calls this
* Get the number of tde tables in this database should always be zero.
* But still, it prevents the cleanup if someone explicitly calls this
* function.
*/
if (!redo)

@ -18,7 +18,7 @@
/* Returns package version */
const char*
const char *
pg_tde_package_string(void)
{
return PACKAGE_STRING;
@ -29,7 +29,7 @@ pg_tde_package_name(void)
{
return PACKAGE_NAME;
}
const char*
const char *
pg_tde_package_version(void)
{
return PACKAGE_VERSION;

@ -101,8 +101,8 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
else if (IsA(parsetree, CreateStmt))
{
CreateStmt *stmt = (CreateStmt *) parsetree;
TDEPrincipalKey * principal_key;
Oid tablespace_oid;
TDEPrincipalKey *principal_key;
Oid tablespace_oid;
tdeCurrentCreateEvent.eventType = TDE_TABLE_CREATE_EVENT;
tdeCurrentCreateEvent.relation = stmt->relation;
@ -110,15 +110,16 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
if (stmt->accessMethod && strcmp(stmt->accessMethod, "tde_heap") == 0)
{
tdeCurrentCreateEvent.encryptMode = true;
} else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] ==0) && strcmp(default_table_access_method, "tde_heap") == 0)
}
else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] == 0) && strcmp(default_table_access_method, "tde_heap") == 0)
{
tdeCurrentCreateEvent.encryptMode = true;
}
if(tdeCurrentCreateEvent.encryptMode)
if (tdeCurrentCreateEvent.encryptMode)
{
tablespace_oid = stmt->tablespacename != NULL ? get_tablespace_oid(stmt->tablespacename, false)
: MyDatabaseTableSpace;
tablespace_oid = stmt->tablespacename != NULL ? get_tablespace_oid(stmt->tablespacename, false)
: MyDatabaseTableSpace;
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);
principal_key = GetPrincipalKey(MyDatabaseId, tablespace_oid, LW_SHARED);
LWLockRelease(tde_lwlock_enc_keys());
@ -151,7 +152,10 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
}
}
// TODO: also check for tablespace change, if current or new AM is tde_heap!
/*
* TODO: also check for tablespace change, if current or new AM is
* tde_heap!
*/
if (tdeCurrentCreateEvent.encryptMode)
{

@ -14,18 +14,19 @@ typedef struct TDESMgrRelationData
{
/* parent data */
SMgrRelationData reln;
/*
* for md.c; per-fork arrays of the number of open segments
* (md_num_open_segs) and the segments themselves (md_seg_fds).
*/
int md_num_open_segs[MAX_FORKNUM + 1];
int md_num_open_segs[MAX_FORKNUM + 1];
struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1];
bool encrypted_relation;
RelKeyData relKey;
} TDESMgrRelationData;
} TDESMgrRelationData;
typedef TDESMgrRelationData *TDESMgrRelation;
typedef TDESMgrRelationData * TDESMgrRelation;
/*
* we only encrypt main and init forks
@ -36,48 +37,51 @@ tde_is_encryption_required(TDESMgrRelation tdereln, ForkNumber forknum)
return (tdereln->encrypted_relation && (forknum == MAIN_FORKNUM || forknum == INIT_FORKNUM));
}
static RelKeyData*
static RelKeyData *
tde_smgr_get_key(SMgrRelation reln)
{
TdeCreateEvent *event;
RelKeyData *rkd;
TDEPrincipalKey *pk;
if(IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber))
if (IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber))
{
// do not try to encrypt/decrypt catalog tables
/* do not try to encrypt/decrypt catalog tables */
return NULL;
}
LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED);
pk = GetPrincipalKey(reln->smgr_rlocator.locator.dbOid, reln->smgr_rlocator.locator.spcOid, LW_SHARED);
LWLockRelease(tde_lwlock_enc_keys());
if(pk == NULL)
if (pk == NULL)
{
return NULL;
}
event = GetCurrentTdeCreateEvent();
// see if we have a key for the relation, and return if yes
/* see if we have a key for the relation, and return if yes */
rkd = GetSMGRRelationKey(reln->smgr_rlocator.locator);
if(rkd != NULL)
if (rkd != NULL)
{
return rkd;
}
// if this is a CREATE TABLE, we have to generate the key
if(event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT)
/* if this is a CREATE TABLE, we have to generate the key */
if (event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT)
{
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
}
// if this is a CREATE INDEX, we have to load the key based on the table
if(event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT)
/* if this is a CREATE INDEX, we have to load the key based on the table */
if (event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT)
{
// For now keep it simple and create separate key for indexes
// Later we might modify the map infrastructure to support the same keys
/* For now keep it simple and create separate key for indexes */
/*
* Later we might modify the map infrastructure to support the same
* keys
*/
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
}
@ -86,9 +90,9 @@ tde_smgr_get_key(SMgrRelation reln)
static void
tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void **buffers, BlockNumber nblocks, bool skipFsync)
const void **buffers, BlockNumber nblocks, bool skipFsync)
{
TDESMgrRelation tdereln = (TDESMgrRelation)reln;
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey;
if (!tde_is_encryption_required(tdereln, forknum))
@ -97,26 +101,28 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
}
else
{
char *local_blocks = palloc(BLCKSZ * (nblocks + 1));
char *local_blocks_aligned = (char *)TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
char *local_blocks = palloc(BLCKSZ * (nblocks + 1));
char *local_blocks_aligned = (char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
const void **local_buffers = palloc(sizeof(void *) * nblocks);
AesInit();
for(int i = 0; i < nblocks; ++i )
for (int i = 0; i < nblocks; ++i)
{
int out_len = BLCKSZ;
int out_len = BLCKSZ;
local_buffers[i] = &local_blocks_aligned[i * BLCKSZ];
BlockNumber bn = blocknum + i;
unsigned char iv[16] = {0,};
memcpy(iv+4, &bn, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char**)buffers)[i], BLCKSZ, local_buffers[i], &out_len);
memcpy(iv + 4, &bn, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, local_buffers[i], &out_len);
}
mdwritev(reln, forknum, blocknum,
local_buffers, nblocks, skipFsync);
local_buffers, nblocks, skipFsync);
pfree(local_blocks);
pfree(local_buffers);
@ -125,9 +131,9 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
static void
tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
const void *buffer, bool skipFsync)
const void *buffer, bool skipFsync)
{
TDESMgrRelation tdereln = (TDESMgrRelation)reln;
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey;
if (!tde_is_encryption_required(tdereln, forknum))
@ -137,8 +143,8 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
else
{
char *local_blocks = palloc(BLCKSZ * (1 + 1));
char *local_blocks_aligned = (char *)TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
int out_len = BLCKSZ;
char *local_blocks_aligned = (char *) TYPEALIGN(PG_IO_ALIGN_SIZE, local_blocks);
int out_len = BLCKSZ;
unsigned char iv[16] = {
0,
};
@ -146,7 +152,7 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
AesInit();
memcpy(iv + 4, &blocknum, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char *)buffer), BLCKSZ, local_blocks_aligned, &out_len);
AesEncrypt(rkd->internal_key.key, iv, ((char *) buffer), BLCKSZ, local_blocks_aligned, &out_len);
mdextend(reln, forknum, blocknum, local_blocks_aligned, skipFsync);
@ -156,10 +162,10 @@ tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
static void
tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
void **buffers, BlockNumber nblocks)
void **buffers, BlockNumber nblocks)
{
int out_len = BLCKSZ;
TDESMgrRelation tdereln = (TDESMgrRelation)reln;
int out_len = BLCKSZ;
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *rkd = &tdereln->relKey;
mdreadv(reln, forknum, blocknum, buffers, nblocks);
@ -169,42 +175,60 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
AesInit();
for(int i = 0; i < nblocks; ++i)
for (int i = 0; i < nblocks; ++i)
{
bool allZero = true;
bool allZero = true;
BlockNumber bn = blocknum + i;
unsigned char iv[16] = {0,};
for(int j = 0; j < 32; ++j)
for (int j = 0; j < 32; ++j)
{
if(((char**)buffers)[i][j] != 0)
if (((char **) buffers)[i][j] != 0)
{
// Postgres creates all zero blocks in an optimized route, which we do not try
// to encrypt.
// Instead we detect if a block is all zero at decryption time, and
// leave it as is.
// This could be a security issue later, but it is a good first prototype
/*
* Postgres creates all zero blocks in an optimized route,
* which we do not try
*/
/* to encrypt. */
/*
* Instead we detect if a block is all zero at decryption
* time, and
*/
/* leave it as is. */
/*
* This could be a security issue later, but it is a good
* first prototype
*/
allZero = false;
break;
}
}
if(allZero)
if (allZero)
continue;
memcpy(iv+4, &bn, sizeof(BlockNumber));
memcpy(iv + 4, &bn, sizeof(BlockNumber));
AesDecrypt(rkd->internal_key.key, iv, ((char **)buffers)[i], BLCKSZ, ((char **)buffers)[i], &out_len);
AesDecrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, ((char **) buffers)[i], &out_len);
}
}
static void
tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{
TDESMgrRelation tdereln = (TDESMgrRelation)reln;
// This is the only function that gets called during actual CREATE TABLE/INDEX (EVENT TRIGGER)
// so we create the key here by loading it
// Later calls then decide to encrypt or not based on the existence of the key
RelKeyData* key = tde_smgr_get_key(reln);
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
/*
* This is the only function that gets called during actual CREATE
* TABLE/INDEX (EVENT TRIGGER)
*/
/* so we create the key here by loading it */
/*
* Later calls then decide to encrypt or not based on the existence of the
* key
*/
RelKeyData *key = tde_smgr_get_key(reln);
if (key)
{
tdereln->encrypted_relation = true;
@ -224,8 +248,9 @@ tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
static void
tde_mdopen(SMgrRelation reln)
{
TDESMgrRelation tdereln = (TDESMgrRelation)reln;
TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *key = tde_smgr_get_key(reln);
if (key)
{
tdereln->encrypted_relation = true;
@ -260,16 +285,18 @@ static const struct f_smgr tde_smgr = {
.smgr_registersync = mdregistersync,
};
void RegisterStorageMgr(void)
void
RegisterStorageMgr(void)
{
tde_smgr_id = smgr_register(&tde_smgr, sizeof(TDESMgrRelationData));
// TODO: figure out how this part should work in a real extension
storage_manager_id = tde_smgr_id;
/* TODO: figure out how this part should work in a real extension */
storage_manager_id = tde_smgr_id;
}
#else
void RegisterStorageMgr(void)
void
RegisterStorageMgr(void)
{
}
#endif /* PERCONA_EXT */
#endif /* PERCONA_EXT */

@ -20,14 +20,14 @@
typedef struct PendingMapEntryDelete
{
off_t map_entry_offset; /* map entry offset */
RelFileLocator rlocator; /* main for use as relation OID */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
struct PendingMapEntryDelete *next; /* linked-list link */
off_t map_entry_offset; /* map entry offset */
RelFileLocator rlocator; /* main for use as relation OID */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
struct PendingMapEntryDelete *next; /* linked-list link */
} PendingMapEntryDelete;
static PendingMapEntryDelete *pendingDeletes = NULL; /* head of linked list */
static PendingMapEntryDelete *pendingDeletes = NULL; /* head of linked list */
static void do_pending_deletes(bool isCommit);
static void reassign_pending_deletes_to_parent_xact(void);
@ -37,53 +37,55 @@ static void pending_delete_cleanup(void);
void
pg_tde_xact_callback(XactEvent event, void *arg)
{
if (event == XACT_EVENT_PARALLEL_ABORT ||
event == XACT_EVENT_ABORT)
{
ereport(DEBUG2,
(errmsg("pg_tde_xact_callback: aborting transaction")));
do_pending_deletes(false);
}
else if (event == XACT_EVENT_COMMIT)
{
do_pending_deletes(true);
pending_delete_cleanup();
}
else if (event == XACT_EVENT_PREPARE)
{
pending_delete_cleanup();
}
if (event == XACT_EVENT_PARALLEL_ABORT ||
event == XACT_EVENT_ABORT)
{
ereport(DEBUG2,
(errmsg("pg_tde_xact_callback: aborting transaction")));
do_pending_deletes(false);
}
else if (event == XACT_EVENT_COMMIT)
{
do_pending_deletes(true);
pending_delete_cleanup();
}
else if (event == XACT_EVENT_PREPARE)
{
pending_delete_cleanup();
}
}
void
pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg)
SubTransactionId parentSubid, void *arg)
{
/* TODO: takle all possible transaction states */
if (event == SUBXACT_EVENT_ABORT_SUB)
{
ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: aborting subtransaction")));
do_pending_deletes(false);
} else if (event == SUBXACT_EVENT_COMMIT_SUB)
{
ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: committing subtransaction")));
reassign_pending_deletes_to_parent_xact();
}
/* TODO: takle all possible transaction states */
if (event == SUBXACT_EVENT_ABORT_SUB)
{
ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: aborting subtransaction")));
do_pending_deletes(false);
}
else if (event == SUBXACT_EVENT_COMMIT_SUB)
{
ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: committing subtransaction")));
reassign_pending_deletes_to_parent_xact();
}
}
void
RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit)
{
PendingMapEntryDelete *pending;
pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete));
pending->map_entry_offset = map_entry_offset;
memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator));
pending->atCommit = atCommit; /* delete if abort */
pending->nestLevel = GetCurrentTransactionNestLevel();
pending->next = pendingDeletes;
pendingDeletes = pending;
PendingMapEntryDelete *pending;
pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete));
pending->map_entry_offset = map_entry_offset;
memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator));
pending->atCommit = atCommit; /* delete if abort */
pending->nestLevel = GetCurrentTransactionNestLevel();
pending->next = pendingDeletes;
pendingDeletes = pending;
}
/*
@ -91,15 +93,15 @@ RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset,
*
* This also runs when aborting a subxact; we want to clean up a failed
* subxact immediately.
*
*
*/
static void
do_pending_deletes(bool isCommit)
{
int nestLevel = GetCurrentTransactionNestLevel();
PendingMapEntryDelete *pending;
PendingMapEntryDelete *prev;
PendingMapEntryDelete *next;
int nestLevel = GetCurrentTransactionNestLevel();
PendingMapEntryDelete *pending;
PendingMapEntryDelete *prev;
PendingMapEntryDelete *next;
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
@ -114,21 +116,21 @@ do_pending_deletes(bool isCommit)
continue;
}
/* unlink list entry first, so we don't retry on failure */
if (prev)
prev->next = next;
else
pendingDeletes = next;
/* do deletion if called for */
if (pending->atCommit == isCommit)
{
ereport(LOG,
(errmsg("pg_tde_xact_callback: deleting entry at offset %d",
(int)(pending->map_entry_offset))));
pg_tde_free_key_map_entry(&pending->rlocator, MAP_ENTRY_VALID, pending->map_entry_offset);
}
pfree(pending);
/* prev does not change */
/* unlink list entry first, so we don't retry on failure */
if (prev)
prev->next = next;
else
pendingDeletes = next;
/* do deletion if called for */
if (pending->atCommit == isCommit)
{
ereport(LOG,
(errmsg("pg_tde_xact_callback: deleting entry at offset %d",
(int) (pending->map_entry_offset))));
pg_tde_free_key_map_entry(&pending->rlocator, MAP_ENTRY_VALID, pending->map_entry_offset);
}
pfree(pending);
/* prev does not change */
}
@ -143,20 +145,20 @@ do_pending_deletes(bool isCommit)
* 1. Only top level transaction can perform on-commit deletes.
* 2. Subtransaction and top level transaction can perform on-abort deletes.
* So we have to decrement the nesting level of pending deletes to reassing them to the parent transaction
* if subtransaction was not self aborted. In other words if subtransaction state is commited all its pending
* if subtransaction was not self aborted. In other words if subtransaction state is commited all its pending
* deletes are reassigned to the parent transaction.
*/
static void
static void
reassign_pending_deletes_to_parent_xact(void)
{
PendingMapEntryDelete *pending;
int nestLevel = GetCurrentTransactionNestLevel();
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel == nestLevel)
pending->nestLevel--;
}
PendingMapEntryDelete *pending;
int nestLevel = GetCurrentTransactionNestLevel();
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel == nestLevel)
pending->nestLevel--;
}
}
/*
@ -169,13 +171,13 @@ reassign_pending_deletes_to_parent_xact(void)
static void
pending_delete_cleanup(void)
{
PendingMapEntryDelete *pending;
PendingMapEntryDelete *next;
for (pending = pendingDeletes; pending != NULL; pending = next)
{
next = pending->next;
pendingDeletes = next;
pfree(pending);
}
PendingMapEntryDelete *pending;
PendingMapEntryDelete *next;
for (pending = pendingDeletes; pending != NULL; pending = next)
{
next = pending->next;
pendingDeletes = next;
pfree(pending);
}
}

@ -0,0 +1,113 @@
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
CurlString
FileKeyring
GenericKeyring
HeapPageFreeze
HeapPageFreeze
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapTupleFreeze
HeapTupleFreeze
IndexDeleteCounts
IndexDeleteCounts
IndexFetchHeapData
IndexFetchHeapData
InternalKey
JsonKeringSemState
JsonKeyringField
JsonKeyringState
JsonVaultRespField
JsonVaultRespSemState
JsonVaultRespState
KeyProviders
KeyringProvideRecord
KeyringProviderXLRecord
KeyringReturnCode
LVPagePruneState
LVRelState
LVRelState
LVSavedErrInfo
LVSavedErrInfo
LogicalRewriteMappingData
LogicalRewriteMappingData
PendingMapEntryDelete
ProviderScanType
PruneFreezeResult
RelKeyCache
RelKeyCacheRec
RelKeyData
RewriteMappingDataEntry
RewriteMappingDataEntry
RewriteMappingFile
RewriteMappingFile
RewriteStateData
RewriteStateData
RewriteStateData
RewriteStateData *RewriteState;
TDEBufferHeapTupleTableSlot
TDEFileHeader
TDEKeyringRoutine
TDELocalState
TDELockTypes
TDEMapEntry
TDEMapFilePath
TDEPrincipalKey
TDEPrincipalKeyId
TDEPrincipalKeyInfo
TDEShmemSetupRoutine
TdeCreateEvent
TdeCreateEventType
TdeKeyProviderInfoSharedState
TdePrincipalKeySharedState
TdePrincipalKeylocalState
TdeSharedState
VaultV2Keyring
XLogExtensionInstall
XLogPrincipalKeyRotate
XLogRelKey
itemIdCompactData
itemIdCompactData
keyData
keyInfo
keyName
xl_multi_insert_tuple
xl_multi_insert_tuple
xl_tdeheap_confirm
xl_tdeheap_confirm
xl_tdeheap_delete
xl_tdeheap_delete
xl_tdeheap_freeze_page
xl_tdeheap_freeze_plan
xl_tdeheap_header
xl_tdeheap_header
xl_tdeheap_inplace
xl_tdeheap_inplace
xl_tdeheap_insert
xl_tdeheap_insert
xl_tdeheap_lock
xl_tdeheap_lock
xl_tdeheap_lock_updated
xl_tdeheap_lock_updated
xl_tdeheap_multi_insert
xl_tdeheap_multi_insert
xl_tdeheap_new_cid
xl_tdeheap_new_cid
xl_tdeheap_prune
xl_tdeheap_prune
xl_tdeheap_rewrite_mapping
xl_tdeheap_rewrite_mapping
xl_tdeheap_truncate
xl_tdeheap_truncate
xl_tdeheap_update
xl_tdeheap_update
xl_tdeheap_vacuum
xl_tdeheap_visible
xl_tdeheap_visible
xlhp_freeze_plan
xlhp_freeze_plans
xlhp_prune_items
Loading…
Cancel
Save