PolarDBforPostgreSQL/external/polar_tde_utils/polar_tde_utils.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;
}