diff --git a/src/backend/storage/encryption/enc_openssl.c b/src/backend/storage/encryption/enc_openssl.c index 95f165f..4a62b35 100644 --- a/src/backend/storage/encryption/enc_openssl.c +++ b/src/backend/storage/encryption/enc_openssl.c @@ -28,6 +28,10 @@ #include #endif +#ifdef FRONTEND +#include "common/logging.h" +#endif + /* * prototype for the EVP functions that return an algorithm, e.g. * EVP_aes_128_cbc(). @@ -83,12 +87,14 @@ createCipherContext(void) if (MyCipherCtx != NULL) return; +#ifndef FRONTEND if (EncMemoryCtx == NULL) EncMemoryCtx = AllocSetContextCreate(TopMemoryContext, "db encryption context", ALLOCSET_DEFAULT_SIZES); old_ctx = MemoryContextSwitchTo(EncMemoryCtx); +#endif cctx = (CipherCtx *) palloc(sizeof(CipherCtx)); @@ -112,7 +118,9 @@ createCipherContext(void) /* Set my cipher context and key size */ MyCipherCtx = cctx; +#ifndef FRONTEND MemoryContextSwitchTo(old_ctx); +#endif } /* Create openssl's key derivation context */ diff --git a/src/backend/storage/encryption/kmgr.c b/src/backend/storage/encryption/kmgr.c index a9638c6..801168a 100644 --- a/src/backend/storage/encryption/kmgr.c +++ b/src/backend/storage/encryption/kmgr.c @@ -15,10 +15,20 @@ #include +#ifndef FRONTEND #include "funcapi.h" -#include "miscadmin.h" #include "pgstat.h" +#include "storage/lwlock.h" +#else +#include "common/logging.h" +#include "storage/enc_common.h" +#include "lib/stringinfo.h" +#include "common/controldata_utils.h" +#include "catalog/pg_control.h" +#endif +#include "miscadmin.h" +#include "storage/enc_common.h" #include "access/xlog.h" #include "common/sha2.h" #include "storage/encryption.h" @@ -57,6 +67,9 @@ static bool verify_passphrase(char *passphrase, int passlen, WrappedEncKeyWithHmac *rdek, WrappedEncKeyWithHmac *wdek); +static void printfkey(char *prompt, char *key, unsigned int len); + +#ifndef FRONTEND /* * This func must be called ONCE on system install. we retrive KEK, * generate RDEK and WDEK etc. @@ -147,6 +160,7 @@ BootStrapKmgr(int bootstrap_data_encryption_cipher) /* return keys and HMACs generated during bootstrap */ return kmgrinfo; } +#endif /* * Run cluster_passphrase_command @@ -192,7 +206,12 @@ run_cluster_passphrase_command(char *buf, int size) appendStringInfoChar(&command, p[0]); } +#ifndef FRONTEND fh = OpenPipeStream(command.data, "r"); +#else + fh = popen(command.data, "r"); +#endif + if (fh == NULL) ereport(ERROR, (errcode_for_file_access(), @@ -211,7 +230,12 @@ run_cluster_passphrase_command(char *buf, int size) } } +#ifndef FRONTEND pclose_rc = ClosePipeStream(fh); +#else + pclose_rc = pclose(fh); +#endif + if (pclose_rc == -1) { pfree(command.data); @@ -239,6 +263,7 @@ run_cluster_passphrase_command(char *buf, int size) return len; } +#ifndef FRONTEND /* * Get encryption key passphrase and verify it, then get the un-encrypted * RDEK and WDEK. This function is called by postmaster at startup time. @@ -285,6 +310,96 @@ InitializeKmgr(void) elog(ERROR, "unwrapped WAL encryptoin key size is invalid, got %d expected %d", unwrapped_size, EncryptionKeySize); } +#endif + +/* + * Print the value of the key as octal. + * prompt is the description of the key. + */ +static void +printfkey(char *prompt, char *key, unsigned int len) +{ + int i = 0; + if (!key) + return; + printf("#%s#: ",prompt); + + for(i = 0; i < len; i++) + { + printf("%04x", key[i]); + if(key[i] == '\0') + break; + } + printf("\n"); +} + +#ifdef FRONTEND +/* + * Get and decrypt the relKey and walKey from Control file. + */ +void +getKmgr(char *pgdatapath, char *cluster_passphrase, char *progname) +{ + WrappedEncKeyWithHmac *wrapped_rdek; + WrappedEncKeyWithHmac *wrapped_wdek; + char passphrase[TDE_MAX_PASSPHRASE_LEN]; + int len; + int wrapped_keysize; + int unwrapped_size; + ControlFileData *ControlFile; + bool crc_ok; + + ControlFile = get_controlfile(pgdatapath, &crc_ok); + + data_encryption_cipher = ControlFile->data_encryption_cipher; + + if (!DataEncryptionEnabled()) + return; + else + { + if (!cluster_passphrase) + { + pg_log_error("no source cluster passphrase command (--cluster-passphrase-command)"); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(1); + } + } + + assign_data_encryption_cipher(ControlFile->data_encryption_cipher, NULL); + + cluster_passphrase_command = cluster_passphrase; + + /* + * Get two keys from control file. We unwrap them as they are wrapped by KEK. + */ + + wrapped_rdek = &(ControlFile->tde_rdek); + wrapped_wdek = &(ControlFile->tde_wdek); + + /* Get key encryption key */ + len = run_cluster_passphrase_command(passphrase, TDE_MAX_PASSPHRASE_LEN); + + wrapped_keysize = EncryptionKeySize + TDE_DEK_WRAP_VALUE_SIZE; + + /* Verify the given passphrase */ + if (!verify_passphrase(passphrase, len, wrapped_rdek, wrapped_wdek)) + ereport(ERROR, + (errmsg("cluster passphrase does not match expected passphrase"))); + pg_unwrap_key(keyEncKey, TDE_KEK_SIZE, + wrapped_rdek->key, wrapped_keysize, + relEncKey, &unwrapped_size); + if (unwrapped_size != EncryptionKeySize) + elog(ERROR, "unwrapped relation encryption key size is invalid, got %d expected %d", + unwrapped_size, EncryptionKeySize); + + pg_unwrap_key(keyEncKey, TDE_KEK_SIZE, + wrapped_wdek->key, wrapped_keysize, + walEncKey, &unwrapped_size); + if (unwrapped_size != EncryptionKeySize) + elog(ERROR, "unwrapped WAL encryptoin key size is invalid, got %d expected %d", + unwrapped_size, EncryptionKeySize); +} +#endif /* * Hash the given passphrase and extract it into KEK and HMAC diff --git a/src/common/logging.c b/src/common/logging.c index 895da71..93e2837 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -235,3 +235,33 @@ pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_list a free(buf); } + +#ifdef FRONTEND +char * +errcode_for_file_access() +{ + fprintf(stderr, "%s\n", "Error Code : XX000"); + return "XX000"; +} + +char * +pg_log_errmsg(const char *pg_restrict fmt,...) +{ + char msg[512]; + va_list ap; + + va_start(ap, fmt); + //vsnprintf(msg, 512, fmt, ap); + pg_log_generic_v(PG_LOG_ERROR, fmt, ap); + va_end(ap); + //fprintf(stderr, "%s\n", msg); + return msg; +} + +void +pg_log_ereport(const char *value,...) +{ + if (!value && strcmp("", value)) + fprintf(stderr, "%s\n", value); +} +#endif diff --git a/src/include/common/logging.h b/src/include/common/logging.h index 4a28e9a..b007a48 100644 --- a/src/include/common/logging.h +++ b/src/include/common/logging.h @@ -57,6 +57,22 @@ enum pg_log_level extern enum pg_log_level __pg_log_level; +#ifndef LOG + +enum elog_level +{ + LOG = 0, + LOG_SERVER_ONLY, + INFO, + NOTICE, + WARNING, + ERROR, +}; + +extern enum elog_level __elog_level; + +#endif + /* * Kind of a hack to be able to produce the psql output exactly as required by * the regression tests. @@ -71,6 +87,10 @@ void pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *l void pg_log_generic(enum pg_log_level level, const char *pg_restrict fmt,...) pg_attribute_printf(2, 3); void pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_list ap) pg_attribute_printf(2, 0); +#ifdef FRONTEND +void pg_log_ereport(const char *value,...); +char *pg_log_errmsg(const char *pg_restrict fmt,...); +#endif #define pg_log_fatal(...) do { \ if (likely(__pg_log_level <= PG_LOG_FATAL)) pg_log_generic(PG_LOG_FATAL, __VA_ARGS__); \ @@ -92,4 +112,23 @@ void pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_ if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) pg_log_generic(PG_LOG_DEBUG, __VA_ARGS__); \ } while(0) +#ifdef FRONTEND +#define errdetail errmsg +#define errdetail_internal pg_log_errmsg +#define errmsg pg_log_errmsg +#define ereport(elevel, rest) { \ + if (elevel == ERROR) {\ + pg_log_ereport rest; \ + exit(1); \ + } \ +} + +#define elog(elevel, ...) { \ + if (elevel == ERROR) {\ + pg_log_generic(PG_LOG_ERROR, __VA_ARGS__); \ + exit(1); \ + } \ +} +#endif + #endif /* COMMON_LOGGING_H */ diff --git a/src/include/storage/kmgr.h b/src/include/storage/kmgr.h index 5a484f8..5bdc91d 100644 --- a/src/include/storage/kmgr.h +++ b/src/include/storage/kmgr.h @@ -64,4 +64,8 @@ extern void InitializeKmgr(void); extern const char *KmgrGetRelationEncryptionKey(void); extern const char *KmgrGetWALEncryptionKey(void); +#ifdef FRONTEND +void getKmgr(char *pgdatapath, char *cluster_passphras, char* progname); +#endif + #endif /* KMGR_H */ diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index ba0b7f6..46d8a9d 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -117,6 +117,7 @@ * prevents gcc from making the unreachability deduction at optlevel -O0. *---------- */ +#ifndef FRONTEND #ifdef HAVE__BUILTIN_CONSTANT_P #define ereport_domain(elevel, domain, rest) \ do { \ @@ -142,6 +143,7 @@ ereport_domain(elevel, TEXTDOMAIN, rest) #define TEXTDOMAIN NULL +#endif extern bool errstart(int elevel, const char *filename, int lineno, const char *funcname, const char *domain); @@ -149,7 +151,9 @@ extern void errfinish(int dummy,...); extern int errcode(int sqlerrcode); +#ifndef FRONTEND extern int errcode_for_file_access(void); +#endif extern int errcode_for_socket_access(void); extern int errmsg(const char *fmt,...) pg_attribute_printf(1, 2); @@ -213,6 +217,7 @@ extern int getinternalerrposition(void); * Note that historically elog() has called elog_start (which saves errno) * before evaluating "elevel", so we preserve that behavior here. */ +#ifndef FRONTEND #ifdef HAVE__BUILTIN_CONSTANT_P #define elog(elevel, ...) \ do { \ @@ -235,6 +240,7 @@ extern int getinternalerrposition(void); } \ } while(0) #endif /* HAVE__BUILTIN_CONSTANT_P */ +#endif extern void elog_start(const char *filename, int lineno, const char *funcname); extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf(2, 3);