304 lines
10 KiB
C
304 lines
10 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* polar_tde_utils.c
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* external/polar_tde_utils/polar_tde_utils.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
#include "storage/enc_common.h"
|
|
#include "storage/kmgr.h"
|
|
#include "storage/enc_cipher.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/guc.h"
|
|
#include "funcapi.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "miscadmin.h"
|
|
|
|
//POLAR: declaration for heap_form_tuple
|
|
#include "access/htup_details.h"
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
|
|
Datum polar_tde_update_kmgr_file(PG_FUNCTION_ARGS);
|
|
PG_FUNCTION_INFO_V1(polar_tde_update_kmgr_file);
|
|
|
|
Datum polar_tde_kmgr_info_view(PG_FUNCTION_ARGS);
|
|
PG_FUNCTION_INFO_V1(polar_tde_kmgr_info_view);
|
|
|
|
Datum polar_tde_check_kmgr_file(PG_FUNCTION_ARGS);
|
|
PG_FUNCTION_INFO_V1(polar_tde_check_kmgr_file);
|
|
|
|
Datum
|
|
polar_tde_update_kmgr_file(PG_FUNCTION_ARGS)
|
|
{
|
|
char *polar_cluster_passphrase_command_new = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
KmgrFileData *kmgrfile;
|
|
keydata_t key_enc_key_new[TDE_KEK_SIZE];
|
|
char passphrase[TDE_MAX_PASSPHRASE_LEN];
|
|
keydata_t hmackey[TDE_HMAC_KEY_SIZE];
|
|
keydata_t *rdek_enc;
|
|
keydata_t *wdek_enc;
|
|
keydata_t *rdek_hmac;
|
|
keydata_t *wdek_hmac;
|
|
int wrapped_keysize;
|
|
int len;
|
|
int size;
|
|
|
|
if (!superuser())
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("must be superuser to execute polar_tde_update_kmgr_file.")));
|
|
|
|
if (data_encryption_cipher == TDE_ENCRYPTION_OFF){
|
|
elog(ERROR, "data_encryption_cipher is off, can not update kmgr file.");
|
|
PG_RETURN_BOOL(false);
|
|
}
|
|
|
|
#ifndef USE_OPENSSL
|
|
elog(ERROR, "Cluster encryption is not supported because OpenSSL is not supported by this build, "
|
|
"compile with --with-openssl to use cluster encryption.");
|
|
PG_RETURN_BOOL(false);
|
|
#endif
|
|
|
|
/* Update the polar_cluster_passphrase_command so we can use the new one */
|
|
SetConfigOption("polar_cluster_passphrase_command",
|
|
polar_cluster_passphrase_command_new,
|
|
PGC_SIGHUP, PGC_S_SESSION);
|
|
|
|
/* Fill out the kmgr file contents */
|
|
kmgrfile = palloc0(sizeof(KmgrFileData));
|
|
kmgrfile->data_encryption_cipher = data_encryption_cipher;
|
|
rdek_enc = kmgrfile->tde_rdek.key;
|
|
rdek_hmac = kmgrfile->tde_rdek.hmac;
|
|
wdek_enc = kmgrfile->tde_wdek.key;
|
|
wdek_hmac = kmgrfile->tde_wdek.hmac;
|
|
|
|
/* Get encryption key passphrase */
|
|
len = run_cluster_passphrase_command(KMGR_PROMPT_MSG,
|
|
passphrase,
|
|
TDE_MAX_PASSPHRASE_LEN);
|
|
|
|
/* Get key encryption key and HMAC key from passphrase */
|
|
get_kek_and_hmackey_from_passphrase(passphrase, len, key_enc_key_new, hmackey);
|
|
|
|
/* Get relation encryption key and wal encryption key from memory */
|
|
|
|
/* Wrap both keys by KEK */
|
|
wrapped_keysize = EncryptionKeySize + TDE_DEK_WRAP_VALUE_SIZE;
|
|
pg_wrap_key(key_enc_key_new, TDE_KEK_SIZE,
|
|
(unsigned char *) KmgrGetRelationEncryptionKey(), EncryptionKeySize,
|
|
rdek_enc, &size);
|
|
if (size != wrapped_keysize){
|
|
elog(ERROR, "wrapped relation encryption key size is invalid, got %d expected %d",
|
|
size, wrapped_keysize);
|
|
PG_RETURN_BOOL(false);
|
|
}
|
|
|
|
pg_wrap_key(key_enc_key_new, TDE_KEK_SIZE,
|
|
(unsigned char *) KmgrGetWALEncryptionKey(), EncryptionKeySize,
|
|
wdek_enc, &size);
|
|
if (size != wrapped_keysize){
|
|
elog(ERROR, "wrapped WAL encryption key size is invalid, got %d expected %d",
|
|
size, wrapped_keysize);
|
|
PG_RETURN_BOOL(false);
|
|
}
|
|
|
|
/* Compute both HMAC */
|
|
pg_compute_hmac(hmackey, TDE_HMAC_KEY_SIZE,
|
|
rdek_enc, wrapped_keysize,
|
|
rdek_hmac);
|
|
pg_compute_hmac(hmackey, TDE_HMAC_KEY_SIZE,
|
|
wdek_enc, wrapped_keysize,
|
|
wdek_hmac);
|
|
|
|
/* write kmgr file to the disk, the kmgr file is very small, so we don't use rename.*/
|
|
write_kmgr_file(kmgrfile);
|
|
pfree(kmgrfile);
|
|
PG_RETURN_BOOL(true);
|
|
}
|
|
|
|
Datum
|
|
polar_tde_check_kmgr_file(PG_FUNCTION_ARGS)
|
|
{
|
|
KmgrFileData *kmgrfile;
|
|
WrappedEncKeyWithHmac *wrapped_rdek;
|
|
WrappedEncKeyWithHmac *wrapped_wdek;
|
|
char passphrase[TDE_MAX_PASSPHRASE_LEN];
|
|
|
|
keydata_t user_kek[TDE_KEK_SIZE];
|
|
keydata_t user_hmackey[TDE_HMAC_KEY_SIZE];
|
|
keydata_t result_hmac[TDE_HMAC_SIZE];
|
|
|
|
keydata_t rel_enc_key_in_file[TDE_MAX_DEK_SIZE];
|
|
keydata_t wal_enc_key_in_file[TDE_MAX_DEK_SIZE];
|
|
|
|
int len;
|
|
int wrapped_keysize;
|
|
int unwrapped_size;
|
|
|
|
bool kmgr_file_is_right = true;
|
|
|
|
if (!superuser())
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("must be superuser to execute polar_tde_check_kmgr_file.")));
|
|
|
|
if (!is_kmgr_file_exist()){
|
|
elog(WARNING, "Can not find the kmgr file, check kmgr file failed!");
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
/* Get contents of kmgr file */
|
|
kmgrfile = polar_read_kmgr_file();
|
|
|
|
if (kmgrfile->kmgr_version_no != KMGR_VERSION_NO){
|
|
elog(WARNING, "kmgr_version_no in the kmgr file is not right!");
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
if (kmgrfile->data_encryption_cipher != data_encryption_cipher){
|
|
elog(WARNING, "data_encryption_cipher in the kmgr file is not right!");
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
/* Get cluster passphrase */
|
|
len = run_cluster_passphrase_command(KMGR_PROMPT_MSG, passphrase, TDE_MAX_PASSPHRASE_LEN);
|
|
|
|
/* Get two wrapped keys stored in kmgr file */
|
|
wrapped_rdek = &(kmgrfile->tde_rdek);
|
|
wrapped_wdek = &(kmgrfile->tde_wdek);
|
|
|
|
wrapped_keysize = EncryptionKeySize + TDE_DEK_WRAP_VALUE_SIZE;
|
|
|
|
get_kek_and_hmackey_from_passphrase(passphrase, len,
|
|
user_kek, user_hmackey);
|
|
|
|
/* Verify both HMACs of RDEK and WDEK */
|
|
pg_compute_hmac(user_hmackey, TDE_HMAC_KEY_SIZE,
|
|
wrapped_rdek->key, wrapped_keysize,
|
|
result_hmac);
|
|
if (memcmp(result_hmac, wrapped_rdek->hmac, TDE_HMAC_SIZE) != 0){
|
|
elog(WARNING, "the hmac of the rel encryption key is not the same as kmgr file."
|
|
"the hmac of the rel encryption key is %s, "
|
|
"the hmac of the rel encryption key from kmgr file is %s",
|
|
result_hmac, wrapped_rdek->hmac);
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
pg_compute_hmac(user_hmackey, TDE_HMAC_KEY_SIZE,
|
|
wrapped_wdek->key, wrapped_keysize,
|
|
result_hmac);
|
|
if (memcmp(result_hmac, wrapped_wdek->hmac, TDE_HMAC_SIZE) != 0){
|
|
elog(WARNING, "the hmac of the wal encryption key is not the same as kmgr file."
|
|
"the hmac of the wal encryption key is %s, "
|
|
"the hmac of the wal encryption key from kmgr file is %s",
|
|
result_hmac, wrapped_wdek->hmac);
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
/* The passphrase is correct, unwrap both RDEK and WDEK */
|
|
pg_unwrap_key(user_kek, TDE_KEK_SIZE,
|
|
wrapped_rdek->key, wrapped_keysize,
|
|
rel_enc_key_in_file, &unwrapped_size);
|
|
if (memcmp(rel_enc_key_in_file, KmgrGetRelationEncryptionKey(), EncryptionKeySize) != 0){
|
|
elog(WARNING, "rel encryption key is not the same as the kmgr file: "
|
|
"rel_enckey in memory is %s, rel_enckey in file is %s",
|
|
KmgrGetRelationEncryptionKey(), rel_enc_key_in_file);
|
|
kmgr_file_is_right = false;
|
|
}
|
|
|
|
pg_unwrap_key(user_kek, TDE_KEK_SIZE,
|
|
wrapped_wdek->key, wrapped_keysize,
|
|
wal_enc_key_in_file, &unwrapped_size);
|
|
if (memcmp(wal_enc_key_in_file, KmgrGetWALEncryptionKey(), EncryptionKeySize) != 0){
|
|
elog(WARNING, "wal encryption key is not the same as the kmgr file: "
|
|
"wal_enckey in memory is %s, rel_enckey in file is %s",
|
|
KmgrGetRelationEncryptionKey(), wal_enc_key_in_file);
|
|
kmgr_file_is_right = false;
|
|
}
|
|
pfree(kmgrfile);
|
|
PG_RETURN_BOOL(kmgr_file_is_right);
|
|
}
|
|
|
|
Datum
|
|
polar_tde_kmgr_info_view(PG_FUNCTION_ARGS)
|
|
{
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
TupleDesc tupdesc;
|
|
Tuplestorestate *tupstore;
|
|
MemoryContext oldcontext;
|
|
HeapTuple tuple;
|
|
Datum values[5];
|
|
bool isnull[5];
|
|
KmgrFileData *kmgrfile;
|
|
|
|
char rel_enc_key_hex[TDE_MAX_DEK_SIZE * 2 + 1];
|
|
char wal_enc_key_hex[TDE_MAX_DEK_SIZE * 2 + 1];
|
|
char key_enc_key_hex[TDE_KEK_SIZE * 2 + 1];
|
|
|
|
if (!superuser())
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
errmsg("must be superuser to execute polar_tde_kmgr_info_view.")));
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
rsinfo->setResult = NULL;
|
|
rsinfo->setDesc = NULL;
|
|
|
|
tupdesc = CreateTemplateTupleDesc(5, false);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "kmgr_version_no",
|
|
INT4OID, -1, 0);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "data_encryption_cipher",
|
|
TEXTOID, -1, 0);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "rdek_key_hex",
|
|
TEXTOID, -1, 0);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wdek_key_hex",
|
|
TEXTOID, -1, 0);
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "kek_enckey_hex",
|
|
TEXTOID, -1, 0);
|
|
|
|
oldcontext = MemoryContextSwitchTo(
|
|
rsinfo->econtext->ecxt_per_query_memory);
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
rsinfo->setResult = tupstore;
|
|
rsinfo->setDesc = tupdesc;
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
memset(isnull, false, sizeof(isnull));
|
|
memset(values, 0, sizeof(values));
|
|
kmgrfile = polar_read_kmgr_file();
|
|
hex_encode(KmgrGetRelationEncryptionKey(), TDE_MAX_DEK_SIZE, rel_enc_key_hex);
|
|
rel_enc_key_hex[TDE_MAX_DEK_SIZE * 2] = '\0';
|
|
hex_encode(KmgrGetWALEncryptionKey(), TDE_MAX_DEK_SIZE, wal_enc_key_hex);
|
|
wal_enc_key_hex[TDE_MAX_DEK_SIZE * 2] = '\0';
|
|
hex_encode(KmgrGetKeyEncryptionKey(), TDE_KEK_SIZE, key_enc_key_hex);
|
|
key_enc_key_hex[TDE_MAX_DEK_SIZE * 2] = '\0';
|
|
|
|
values[0] = Int32GetDatum(kmgrfile->kmgr_version_no);
|
|
values[1] = CStringGetTextDatum(EncryptionCipherString(kmgrfile->data_encryption_cipher));
|
|
values[2] = CStringGetTextDatum(rel_enc_key_hex);
|
|
values[3] = CStringGetTextDatum(wal_enc_key_hex);
|
|
values[4] = CStringGetTextDatum(key_enc_key_hex);
|
|
tuple = heap_form_tuple(tupdesc, values, isnull);
|
|
tuplestore_puttuple(tupstore, tuple);
|
|
tuplestore_donestoring(tupstore);
|
|
pfree(kmgrfile);
|
|
return (Datum) 0;
|
|
}
|
|
|
|
|