From a8d079f5a532cc08e62b43361ae35a0218f6cca8 Mon Sep 17 00:00:00 2001 From: Andreas Karlsson Date: Wed, 4 Jun 2025 15:34:13 +0200 Subject: [PATCH] PG-1592 Return all nulls for key info when no key Since no key being configured is not an error we instead of raising the error we return a tuple with all fields set to NULL. This is a pattern used by other PostgreSQL functions. Also add a more explicit test for pg_tde_verify_server_key(). --- .../pg_tde/expected/default_principal_key.out | 21 +++++-- contrib/pg_tde/expected/key_provider.out | 7 ++- .../pg_tde/src/catalog/tde_principal_key.c | 61 ++++++++----------- contrib/pg_tde/t/expected/rotate_key.out | 42 +++++++++---- contrib/pg_tde/t/expected/wal_encrypt.out | 12 ++++ contrib/pg_tde/t/wal_encrypt.pl | 8 +++ 6 files changed, 96 insertions(+), 55 deletions(-) diff --git a/contrib/pg_tde/expected/default_principal_key.out b/contrib/pg_tde/expected/default_principal_key.out index 114f5e5dba896..b36393ff0aa51 100644 --- a/contrib/pg_tde/expected/default_principal_key.out +++ b/contrib/pg_tde/expected/default_principal_key.out @@ -12,8 +12,11 @@ ERROR: principal key not configured for current database -- Should fail: no default principal key for the server yet SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_default_key_info(); -ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT pg_tde_set_default_key_using_global_key_provider('default-key', 'file-provider', false); pg_tde_set_default_key_using_global_key_provider -------------------------------------------------- @@ -48,8 +51,11 @@ SELECT id, provider_name FROM pg_tde_list_all_global_key_providers(); -- Should fail: no principal key for the database yet SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); -ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + -- Should succeed: "localizes" the default principal key for the database CREATE TABLE test_enc( id SERIAL, @@ -74,8 +80,11 @@ CREATE EXTENSION pg_buffercache; -- Should fail: no principal key for the database yet SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); -ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + -- Should succeed: "localizes" the default principal key for the database CREATE TABLE test_enc( id SERIAL, diff --git a/contrib/pg_tde/expected/key_provider.out b/contrib/pg_tde/expected/key_provider.out index 47ba57bdca8de..89d115e51f59f 100644 --- a/contrib/pg_tde/expected/key_provider.out +++ b/contrib/pg_tde/expected/key_provider.out @@ -1,7 +1,10 @@ CREATE EXTENSION IF NOT EXISTS pg_tde; SELECT * FROM pg_tde_key_info(); -ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_name | key_provider_name | key_provider_id | key_creation_time +----------+-------------------+-----------------+------------------- + | | | +(1 row) + SELECT pg_tde_add_database_key_provider_file('incorrect-file-provider', json_object('foo' VALUE '/tmp/pg_tde_test_keyring.per')); ERROR: key provider value cannot be an object SELECT pg_tde_add_database_key_provider_file('file-provider','/tmp/pg_tde_test_keyring.per'); diff --git a/contrib/pg_tde/src/catalog/tde_principal_key.c b/contrib/pg_tde/src/catalog/tde_principal_key.c index b7d894d823ddb..516ab7ddb4c00 100644 --- a/contrib/pg_tde/src/catalog/tde_principal_key.c +++ b/contrib/pg_tde/src/catalog/tde_principal_key.c @@ -625,64 +625,55 @@ pg_tde_get_key_info(PG_FUNCTION_ARGS, Oid dbOid) Datum values[6]; bool isnull[6]; HeapTuple tuple; - Datum result; TDEPrincipalKey *principal_key; - TimestampTz ts; - GenericKeyring *keyring; - /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")); LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED); + principal_key = GetPrincipalKeyNoDefault(dbOid, LW_SHARED); + if (principal_key == NULL) { - ereport(ERROR, - errmsg("Principal key does not exists for the database"), - errhint("Use set_key interface to set the principal key")); + memset(isnull, true, sizeof(isnull)); } + else + { + GenericKeyring *keyring = GetKeyProviderByID(principal_key->keyInfo.keyringId, principal_key->keyInfo.databaseId); + TimestampTz ts; - keyring = GetKeyProviderByID(principal_key->keyInfo.keyringId, principal_key->keyInfo.databaseId); + values[0] = CStringGetTextDatum(principal_key->keyInfo.name); + isnull[0] = false; - /* Initialize the values and null flags */ + if (keyring) + { + values[1] = CStringGetTextDatum(keyring->provider_name); + isnull[1] = false; + } + else + isnull[1] = true; - /* TEXT: Principal key name */ - values[0] = CStringGetTextDatum(principal_key->keyInfo.name); - isnull[0] = false; - /* TEXT: Keyring provider name */ - if (keyring) - { - values[1] = CStringGetTextDatum(keyring->provider_name); - isnull[1] = false; - } - else - isnull[1] = true; + values[2] = Int32GetDatum(principal_key->keyInfo.keyringId); + isnull[2] = false; - /* INTEGERT: key provider id */ - values[2] = Int32GetDatum(principal_key->keyInfo.keyringId); - isnull[2] = false; + ts = (TimestampTz) principal_key->keyInfo.creationTime.tv_sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY); + ts = (ts * USECS_PER_SEC) + principal_key->keyInfo.creationTime.tv_usec; + values[3] = TimestampTzGetDatum(ts); + isnull[3] = false; - /* TIMESTAMP TZ: Principal key creation time */ - ts = (TimestampTz) principal_key->keyInfo.creationTime.tv_sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY); - ts = (ts * USECS_PER_SEC) + principal_key->keyInfo.creationTime.tv_usec; - values[3] = TimestampTzGetDatum(ts); - isnull[3] = false; + pfree(keyring); + } LWLockRelease(tde_lwlock_enc_keys()); - /* Form the tuple */ tuple = heap_form_tuple(tupdesc, values, isnull); - /* Make the tuple into a datum */ - result = HeapTupleGetDatum(tuple); - - pfree(keyring); - - PG_RETURN_DATUM(result); + PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); } + #endif /* FRONTEND */ /* diff --git a/contrib/pg_tde/t/expected/rotate_key.out b/contrib/pg_tde/t/expected/rotate_key.out index 4f7a729433615..288d9d7a3993e 100644 --- a/contrib/pg_tde/t/expected/rotate_key.out +++ b/contrib/pg_tde/t/expected/rotate_key.out @@ -66,8 +66,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT * FROM test_enc ORDER BY id; id | k ----+--- @@ -96,8 +99,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT * FROM test_enc ORDER BY id; id | k ----+--- @@ -126,8 +132,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT * FROM test_enc ORDER BY id; id | k ----+--- @@ -156,8 +165,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT * FROM test_enc ORDER BY id; id | k ----+--- @@ -176,8 +188,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + SELECT pg_tde_set_key_using_database_key_provider('rotated-key2', 'file-2'); pg_tde_set_key_using_database_key_provider -------------------------------------------- @@ -191,8 +206,11 @@ SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_key_info(); (1 row) SELECT key_provider_id, key_provider_name, key_name FROM pg_tde_server_key_info(); -psql::1: ERROR: Principal key does not exists for the database -HINT: Use set_key interface to set the principal key + key_provider_id | key_provider_name | key_name +-----------------+-------------------+---------- + | | +(1 row) + DROP TABLE test_enc; ALTER SYSTEM RESET pg_tde.inherit_global_providers; -- server restart diff --git a/contrib/pg_tde/t/expected/wal_encrypt.out b/contrib/pg_tde/t/expected/wal_encrypt.out index 27963ea824afd..15f878e0d24a8 100644 --- a/contrib/pg_tde/t/expected/wal_encrypt.out +++ b/contrib/pg_tde/t/expected/wal_encrypt.out @@ -7,6 +7,12 @@ SELECT pg_tde_add_global_key_provider_file('file-keyring-010', '/tmp/pg_tde_test SELECT pg_tde_verify_server_key(); psql::1: ERROR: principal key not configured for current database +SELECT key_name, key_provider_name, key_provider_id FROM pg_tde_server_key_info(); + key_name | key_provider_name | key_provider_id +----------+-------------------+----------------- + | | +(1 row) + SELECT pg_tde_set_server_key_using_global_key_provider('server-key', 'file-keyring-010'); pg_tde_set_server_key_using_global_key_provider ------------------------------------------------- @@ -19,6 +25,12 @@ SELECT pg_tde_verify_server_key(); (1 row) +SELECT key_name, key_provider_name, key_provider_id FROM pg_tde_server_key_info(); + key_name | key_provider_name | key_provider_id +------------+-------------------+----------------- + server-key | file-keyring-010 | -1 +(1 row) + ALTER SYSTEM SET pg_tde.wal_encrypt = on; -- server restart with wal encryption SHOW pg_tde.wal_encrypt; diff --git a/contrib/pg_tde/t/wal_encrypt.pl b/contrib/pg_tde/t/wal_encrypt.pl index c554fb0f3bf58..2799b3b6d238b 100644 --- a/contrib/pg_tde/t/wal_encrypt.pl +++ b/contrib/pg_tde/t/wal_encrypt.pl @@ -25,12 +25,20 @@ PGTDE::psql($node, 'postgres', 'SELECT pg_tde_verify_server_key();'); +PGTDE::psql($node, 'postgres', + 'SELECT key_name, key_provider_name, key_provider_id FROM pg_tde_server_key_info();' +); + PGTDE::psql($node, 'postgres', "SELECT pg_tde_set_server_key_using_global_key_provider('server-key', 'file-keyring-010');" ); PGTDE::psql($node, 'postgres', 'SELECT pg_tde_verify_server_key();'); +PGTDE::psql($node, 'postgres', + 'SELECT key_name, key_provider_name, key_provider_id FROM pg_tde_server_key_info();' +); + PGTDE::psql($node, 'postgres', 'ALTER SYSTEM SET pg_tde.wal_encrypt = on;'); PGTDE::append_to_result_file("-- server restart with wal encryption");