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 <[email protected]> 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 */