On Tue, 3 Mar 2020 at 08:49, Cary Huang <[email protected]> wrote:
>
> Hi Masahiko
> Please see below my comments regarding kms_v4.patch that you have shared
> earlier.
Thank you for reviewing this patch!
>
> (1)
> There is a discrepancy between the documentation and the actual function
> definition. For example in func.sgml, it states pg_wrap_key takes argument in
> text data type but in pg_proc.dat and kmgr.c, the function is defined to take
> argument in bytea data type.
>
> ===> doc/src/sgml/func.sgml
> + <entry>
> + <indexterm>
> + <primary>pg_wrap_key</primary>
> + </indexterm>
> + <literal><function>pg_wrap_key(<parameter>data</parameter>
> <type>text</type>)</function></literal>
> + </entry>
> + <entry>
> + <type>bytea</type>
> + </entry>
>
> ===> src/include/catalog/pg_proc.dat
> +{ oid => '8201', descr => 'wrap the given secret',
> + proname => 'pg_wrap_key',
> + provolatile => 'v', prorettype => 'bytea',
> + proargtypes => 'bytea', prosrc => 'pg_wrap_key' },
>
> ===> src/backend/crypto/kmgr.c
> +Datum
> +pg_wrap_key(PG_FUNCTION_ARGS)
> +{
> + bytea *data = PG_GETARG_BYTEA_PP(0);
> + bytea *res;
> + int datalen;
> + int reslen;
> + int len;
Fixed.
> +
>
> (2)
> I think the documentation needs to make clear the difference between a key
> and a user secret. Some parts of it are trying to mix the 2 terms together
> when they shouldn't. To my understanding, a key is expressed as binary data
> that is actually used in the encryption and decryption operations. A user
> secret, on the other hand, is more like a passphrase, expressed as string,
> that is used to derive a encryption key for subsequent encryption operations.
>
> If I just look at the function names "pg_wrap_key" and "pg_unwrap_key", I
> immediately feel that these functions are used to encapsulate and uncover
> cryptographic key materials. The input and output to these 2 functions should
> all be key materials expressed in bytea data type. In previous email
> discussion, there was only one key material in discussion, called the master
> key (generated during initdb and stored in cluster), and this somehow
> automatically makes people (including myself) associate pg_wrap_key and
> pg_unwrap_key to be used on this master key and raise a bunch of security
> concerns around it.
>
> Having read the documentation provided by the patch describing pg_wrap_key
> and pg_unwrap_key, they seem to serve another purpose. It states that
> pg_wrap_key is used to encrypt a user-supplied secret (text) with the master
> key and produce a wrapped secret while pg_unwrap_key does the opposite, so we
> can prevent user from having to enter the secret in plaintext when using
> pgcrypto functions.
>
> This use case is ok but user secret is not really a cryptographic key
> material is it? It is more similar to a secret passphrase expressed in text
> and pg_wrap_key is merely used to turn the passphrase into a wrapped
> passphrase expressed in bytea.
>
> If I give pg_wrap_key with a real key material expressed in bytea, I will not
> be able to unwrap it properly:
>
> Select pg_unwrap_key
> (pg_wrap_key(E'\\x2b073713476f9f0e761e45c64be8175424d2742e7d53df90b6416f1d84168e8a')
> );
>
> pg_unwrap_key
> ----------------------------------------------
> +\x077\x13Go\x0Ev\x1EEK\x17T$t.}SߐAo\x1D\x16
> (1 row)
>
> Maybe we should rename these SQL functions like this to prevent confusion.
> => pg_wrap_secret (takes a text, returns a bytea)
> => pg_unwrap_secret(takes a bytea, returns a text)
Agreed to change argument types. User secret will be normally text
password as we do with pgcrypto. So probably these functions can cover
most cases. I changed the function name to pg_wrap and pg_unwrap
because these functions generically wrap and unwrap the given data.
>
> if there is a use case for users to encapsulate key materials then we can
> define 2 more wrap functions for these, if there is no use case, don't bother:
> => pg_wrap_key (takes a bytea, returns a bytea)
> => pg_unwrap_key (takes a bytea, returns a bytea)
+1. Like pgcrypto has both pgp_sym_encrypt_bytea and pgp_sym_encrypt,
maybe we can have such functions.
>
> (3)
> I would rephrase "chapter 32: Encryption Key Management Part III. Server
> Administration" documentation like this:
>
> =====================
> PostgreSQL supports Encryption Key Management System, which is enabled when
> PostgreSQL is built with --with-openssl option and cluster_passphrase_command
> is specified during initdb process. The user-provided
> cluster_passphrase_command in postgresql.conf and the
> cluster_passphrase_command specified during initdb process must match,
> otherwise, the database cluster will not start up.
>
> The user-provided cluster passphrase is derived into a Key Encryption Key
> (KEK), which is used to encapsulate the Master Encryption Key generated
> during the initdb process. The encapsulated Master Encryption Key is stored
> inside the database cluster.
>
> Encryption Key Management System provides several functions to allow users to
> use the master encryption key to wrap and unwrap their own encryption secrets
> during encryption and decryption operations. This feature allows users to
> encrypt and decrypt data without knowing the actual key.
> =====================
>
> (4)
> I would rephrase "chapter 32.2: Wrap and Unwrap user secret" documentation
> like this: Note that I rephrase based on (2) and uses pg_(un)wrap_secret
> instead.
>
> =====================
> Encryption key management System provides several functions described in
> Table 9.97, to wrap and unwrap user secrets with the Master Encryption Key,
> which is uniquely and securely stored inside the database cluster.
>
> These functions allow user to encrypt and decrypt user data without having to
> provide user encryption secret in plain text. One possible use case is to use
> encryption key management together with pgcrypto. User wraps the user
> encryption secret with pg_wrap_secret() and passes the wrapped encryption
> secret to the pgcrypto encryption functions. The wrapped secret can be stored
> in the application server or somewhere secured and should be obtained
> promptly for cryptographic operations with pgcrypto.
> [same examples follow after...]
> =====================
Thank you for suggesting the updated sentences. I've updated the docs
based on your suggestions.
Regards,
--
Masahiko Sawada http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
configure | 2 +-
configure.in | 2 +-
doc/src/sgml/config.sgml | 49 ++-
doc/src/sgml/filelist.sgml | 1 +
doc/src/sgml/func.sgml | 60 ++++
doc/src/sgml/key-management.sgml | 142 +++++++++
doc/src/sgml/postgres.sgml | 1 +
doc/src/sgml/ref/initdb.sgml | 19 ++
src/backend/Makefile | 2 +-
src/backend/access/transam/xlog.c | 31 ++
src/backend/bootstrap/bootstrap.c | 7 +-
src/backend/crypto/Makefile | 17 ++
src/backend/crypto/kmgr.c | 289 ++++++++++++++++++
src/backend/postmaster/postmaster.c | 6 +
src/backend/tcop/postgres.c | 8 +
src/backend/utils/misc/guc.c | 25 ++
src/backend/utils/misc/postgresql.conf.sample | 5 +
src/bin/initdb/initdb.c | 34 ++-
src/bin/pg_checksums/pg_checksums.c | 1 +
src/bin/pg_controldata/pg_controldata.c | 3 +
src/common/Makefile | 3 +
src/common/cipher.c | 98 ++++++
src/common/cipher_openssl.c | 149 +++++++++
src/common/kmgr_utils.c | 418 ++++++++++++++++++++++++++
src/include/access/xlog.h | 3 +
src/include/catalog/pg_control.h | 7 +
src/include/catalog/pg_proc.dat | 13 +
src/include/common/cipher.h | 58 ++++
src/include/common/cipher_openssl.h | 39 +++
src/include/common/kmgr_utils.h | 84 ++++++
src/include/crypto/kmgr.h | 27 ++
src/include/pg_config.h.in | 3 +
src/include/utils/guc_tables.h | 1 +
src/test/Makefile | 2 +-
src/test/crypto/.gitignore | 2 +
src/test/crypto/Makefile | 24 ++
src/test/crypto/t/001_basic.pl | 32 ++
src/test/perl/PostgresNode.pm | 15 +-
38 files changed, 1670 insertions(+), 12 deletions(-)