On Tue, 3 Mar 2020 at 08:49, Cary Huang <cary.hu...@highgo.ca> 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(-)

Reply via email to