On Mon, Dec 14, 2020 at 11:16:18PM -0500, Bruce Momjian wrote: > > 1. Previously, we added a variable bootstrap_keys_wrap that is used for > > encryption during initdb. However, since we save the "wrapped" key, we need > > to > > use a global KEK that can be accessed in boot mode to unwrap it before > > use... I > > don't know if that's good. To make it simple, I modified the > > bootstrap_keys_wrap to store the "unwrapped" key so that the encryption > > function can get it correctly. (The variable name should be changed > > accordingly). > > I see what you are saying. We store the wrapped in bootstrap mode, but > the unwrapped in normal mode. There is also the case of when we copy > the keys from an old cluster. I will work on a patch tomorrow and > report back here.
I had not considered that we need the date keys available in bootstrap mode, even if we copied them from another cluster during pg_upgrade. I have updated the diff URLs and attaching a patch showing the changes I made. Basically, I had to separate BootStrapKmgr() into sections: 1. copy or create an empty live key directory 2. get the pass phrase 3. populate the live key directory if we didn't copy it 4. decrypt they keys into a file-scoped variable Thanks for showing me this missing feature. -- Bruce Momjian <br...@momjian.us> https://momjian.us EnterpriseDB https://enterprisedb.com The usefulness of a cup is in its emptiness, Bruce Lee
diff --git a/src/backend/crypto/kmgr.c b/src/backend/crypto/kmgr.c new file mode 100644 index 9143e72..24c5d7f *** a/src/backend/crypto/kmgr.c --- b/src/backend/crypto/kmgr.c *************** static KmgrShmemData *KmgrShmem; *** 50,56 **** char *cluster_passphrase_command = NULL; int file_encryption_keylen = 0; ! CryptoKey bootstrap_keys_wrap[KMGR_MAX_INTERNAL_KEYS]; extern char *bootstrap_old_key_datadir; extern int bootstrap_file_encryption_keylen; --- 50,56 ---- char *cluster_passphrase_command = NULL; int file_encryption_keylen = 0; ! CryptoKey bootstrap_keys[KMGR_MAX_INTERNAL_KEYS]; extern char *bootstrap_old_key_datadir; extern int bootstrap_file_encryption_keylen; *************** static CryptoKey *generate_crypto_key(in *** 65,74 **** void BootStrapKmgr(void) { ! PgKeyWrapCtx *ctx; char passphrase[KMGR_MAX_PASSPHRASE_LEN]; - uint8 KEK_enc[KMGR_ENC_KEY_LEN]; - uint8 KEK_hmac[KMGR_MAC_KEY_LEN]; int passlen; #ifndef USE_OPENSSL --- 65,74 ---- void BootStrapKmgr(void) { ! char live_path[MAXPGPATH]; ! CryptoKey *keys_wrap; ! int nkeys; char passphrase[KMGR_MAX_PASSPHRASE_LEN]; int passlen; #ifndef USE_OPENSSL *************** BootStrapKmgr(void) *** 78,83 **** --- 78,85 ---- errhint("Compile with --with-openssl to use cluster encryption.")))); #endif + snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); + /* copy cluster file encryption keys from an old cluster? */ if (bootstrap_old_key_datadir != NULL) { *************** BootStrapKmgr(void) *** 87,122 **** bootstrap_old_key_datadir, LIVE_KMGR_DIR); copydir(old_key_dir, LIVE_KMGR_DIR, true); } ! /* generate new cluster file encryption keys */ else { ! char live_path[MAXPGPATH]; ! ! if (mkdir(LIVE_KMGR_DIR, pg_dir_create_mode) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create cluster file encryption directory \"%s\": %m", LIVE_KMGR_DIR))); - memset(bootstrap_keys_wrap, 0, sizeof(bootstrap_keys_wrap)); - /* bzero keys on exit */ - on_proc_exit(bzeroKmgrKeys, 0); - - /* Get key encryption key from the passphrase command */ - snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); - passlen = kmgr_run_cluster_passphrase_command(cluster_passphrase_command, - passphrase, KMGR_MAX_PASSPHRASE_LEN, - live_path); - if (passlen < KMGR_MIN_PASSPHRASE_LEN) - ereport(ERROR, - (errmsg("passphrase must be at least %d bytes", - KMGR_MIN_PASSPHRASE_LEN))); - /* Get key encryption key and HMAC key from passphrase */ kmgr_derive_keys(passphrase, passlen, KEK_enc, KEK_hmac); - explicit_bzero(passphrase, passlen); - /* Create temporary key wrap context */ ctx = pg_create_keywrap_ctx(KEK_enc, KEK_hmac); if (!ctx) --- 89,128 ---- bootstrap_old_key_datadir, LIVE_KMGR_DIR); copydir(old_key_dir, LIVE_KMGR_DIR, true); } ! /* create empty directory */ else { ! if (mkdir(LIVE_KMGR_DIR, pg_dir_create_mode) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create cluster file encryption directory \"%s\": %m", LIVE_KMGR_DIR))); + } + + /* + * Get key encryption key from the passphrase command. The passphrase + * command might want to check for the existance of files in the + * live directory, so run this _after_ copying the directory in place. + */ + passlen = kmgr_run_cluster_passphrase_command(cluster_passphrase_command, + passphrase, KMGR_MAX_PASSPHRASE_LEN, + live_path); + if (passlen < KMGR_MIN_PASSPHRASE_LEN) + ereport(ERROR, + (errmsg("passphrase must be at least %d bytes", + KMGR_MIN_PASSPHRASE_LEN))); + + /* generate new cluster file encryption keys */ + if (bootstrap_old_key_datadir == NULL) + { + CryptoKey bootstrap_keys_wrap[KMGR_MAX_INTERNAL_KEYS]; + PgKeyWrapCtx *ctx; + uint8 KEK_enc[KMGR_ENC_KEY_LEN]; + uint8 KEK_hmac[KMGR_MAC_KEY_LEN]; /* Get key encryption key and HMAC key from passphrase */ kmgr_derive_keys(passphrase, passlen, KEK_enc, KEK_hmac); /* Create temporary key wrap context */ ctx = pg_create_keywrap_ctx(KEK_enc, KEK_hmac); if (!ctx) *************** BootStrapKmgr(void) *** 142,149 **** --- 148,177 ---- /* Save data encryption keys to the disk */ KmgrSaveCryptoKeys(LIVE_KMGR_DIR, bootstrap_keys_wrap); + explicit_bzero(bootstrap_keys_wrap, sizeof(bootstrap_keys_wrap)); pg_free_keywrap_ctx(ctx); } + + /* + * We are either decrypting keys we copied from an old cluster, or + * decrypting keys we just wrote above --- either way, we decrypt + * them here and store them in a file-scoped variable for use in + * later encrypting during bootstrap mode. + */ + /* Get the crypto keys from the file */ + keys_wrap = kmgr_get_cryptokeys(LIVE_KMGR_DIR, &nkeys); + Assert(nkeys == KMGR_MAX_INTERNAL_KEYS); + + if (!kmgr_verify_passphrase(passphrase, passlen, keys_wrap, bootstrap_keys, + KMGR_MAX_INTERNAL_KEYS)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cluster passphrase does not match expected passphrase"))); + + /* bzero keys on exit */ + on_proc_exit(bzeroKmgrKeys, 0); + + explicit_bzero(passphrase, passlen); } /* Report shared-memory space needed by KmgrShmem */ *************** void *** 179,187 **** InitializeKmgr(void) { CryptoKey *keys_wrap; char passphrase[KMGR_MAX_PASSPHRASE_LEN]; int passlen; - int nkeys; struct stat buffer; char live_path[MAXPGPATH]; --- 207,215 ---- InitializeKmgr(void) { CryptoKey *keys_wrap; + int nkeys; char passphrase[KMGR_MAX_PASSPHRASE_LEN]; int passlen; struct stat buffer; char live_path[MAXPGPATH]; *************** InitializeKmgr(void) *** 219,234 **** (errcode(ERRCODE_INTERNAL_ERROR), (errmsg("cluster has no data encryption keys")))); - /* Get the crypto keys from the file */ - keys_wrap = kmgr_get_cryptokeys(LIVE_KMGR_DIR, &nkeys); - Assert(nkeys == KMGR_MAX_INTERNAL_KEYS); - /* Get cluster passphrase */ snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); passlen = kmgr_run_cluster_passphrase_command(cluster_passphrase_command, passphrase, KMGR_MAX_PASSPHRASE_LEN, live_path); /* * Verify passphrase and prepare a data encryption key in plaintext in shared memory. */ --- 247,262 ---- (errcode(ERRCODE_INTERNAL_ERROR), (errmsg("cluster has no data encryption keys")))); /* Get cluster passphrase */ snprintf(live_path, sizeof(live_path), "%s/%s", DataDir, LIVE_KMGR_DIR); passlen = kmgr_run_cluster_passphrase_command(cluster_passphrase_command, passphrase, KMGR_MAX_PASSPHRASE_LEN, live_path); + /* Get the crypto keys from the file */ + keys_wrap = kmgr_get_cryptokeys(LIVE_KMGR_DIR, &nkeys); + Assert(nkeys == KMGR_MAX_INTERNAL_KEYS); + /* * Verify passphrase and prepare a data encryption key in plaintext in shared memory. */ *************** static void *** 245,251 **** bzeroKmgrKeys(int status, Datum arg) { if (IsBootstrapProcessingMode()) ! explicit_bzero(bootstrap_keys_wrap, sizeof(bootstrap_keys_wrap)); else explicit_bzero(KmgrShmem->intlKeys, sizeof(KmgrShmem->intlKeys)); } --- 273,279 ---- bzeroKmgrKeys(int status, Datum arg) { if (IsBootstrapProcessingMode()) ! explicit_bzero(bootstrap_keys, sizeof(bootstrap_keys)); else explicit_bzero(KmgrShmem->intlKeys, sizeof(KmgrShmem->intlKeys)); } *************** KmgrGetKey(int id) *** 256,262 **** Assert(id < KMGR_MAX_INTERNAL_KEYS); return (const CryptoKey *) (IsBootstrapProcessingMode() ? ! &(bootstrap_keys_wrap[id]) : &(KmgrShmem->intlKeys[id])); } /* Generate an empty CryptoKey */ --- 284,290 ---- Assert(id < KMGR_MAX_INTERNAL_KEYS); return (const CryptoKey *) (IsBootstrapProcessingMode() ? ! &(bootstrap_keys[id]) : &(KmgrShmem->intlKeys[id])); } /* Generate an empty CryptoKey */