Re: [HACKERS] Support for Secure Transport SSL library on macOS asOpenSSL alternative - Mailing list pgsql-hackers

From Heikki Linnakangas
Subject Re: [HACKERS] Support for Secure Transport SSL library on macOS asOpenSSL alternative
Date
Msg-id 732bde95-a196-eef0-b3ea-536d10ddea25@iki.fi
Whole thread Raw
In response to Re: [HACKERS] Support for Secure Transport SSL library on macOS asOpenSSL alternative  (Daniel Gustafsson <daniel@yesql.se>)
Responses Re: [HACKERS] Support for Secure Transport SSL library on macOS as OpenSSL alternative
List pgsql-hackers
On 27/06/18 21:57, Daniel Gustafsson wrote:
>> On 27 Jun 2018, at 14:32, Daniel Gustafsson <daniel@yesql.se> wrote:
> 
>> Attached is an updated patch for supporting the native macOS Secure Transport
>> library, rebased on top of current master.
> 
> Courtesy of the ever-present Murphy I managed to forget some testcode in
> src/backend/Makefile which broke compilation for builds without secure
> transport, attached v8 patch fixes that.

I've read through this patch now in more detail. Looks pretty good, but 
I have a laundry list of little things below. The big missing item is 
documentation.

--- laundry list begins ---

What exactly does 'ssl_is_server_start' mean? I don't understand that 
mechanism. ISTM it's only checked in load_key(), via 
be_tls_open_server(), which should only be called after be_tls_init(), 
in which case it's always 'true' when it's checked. Should there be an 
Assertion on it or something?

The "-framework" option, being added to CFLAGS, is clang specific. I 
think we need some more autoconf magic, to make this work with gcc.

In be_tls_open_server(), I believe there are several cases of using 
variables uninitialized. For example, load_identity_keychain() doesn't 
always set the 'identity' output parameter, but there's an "if (identity 
== NULL)" check after the call to it. And 'certificates' is left 
uninitialized, if load_identity_keychain() is used. Also, 'dh_len' is 
used uninitialized here in the "if (!dh_buf || dh_len == 0)" line, if 
the 'ssl_dh_params_file' option is not set. Did clang not give warnings 
about these?

> +    /*
> +     * Certificate Revocation List are not supported in the Secure Transport
> +     * API
> +     */

The corresponding client code has a longer comment on that:

> +    /*
> +     * There is no API to load CRL lists in Secure Transport, they can however
> +     * be imported into a Keychain with the commandline application "certtool".
> +     * For libpq to use them, the certificate/key and root certificate needs to
> +     * be using an identity in a Keychain into which the CRL have been
> +     * imported. That needs to be documented.
> +     */

Is it possible to programmatically create a temporary keychain, in 
memory, and load the CRL to it? (I googled a bit, and couldn't find any 
suitable API for it, so I guess not..)


> +    if (ssl_crl_file[0])
> +        ereport(FATAL,
> +                (errmsg("CRL files not supported with Secure Transport")));

I think this should be COMMERROR, like other errors around this. We 
don't want to pass that error message to the client. Although I guess it 
won't reach the client as we haven't negotiated TLS yet.

> +    /*
> +     * We use kTryAuthenticate here since we don't know which sslmode the
> +     * client is using. If we were to use kAlwaysAuthenticate then sslmode
> +     * require won't work as intended.
> +     */
> +    if (ssl_loaded_verify_locations)
> +        SSLSetClientSideAuthenticate((SSLContextRef) port->ssl, kTryAuthenticate);

That comment sounds wrong. This is in backend code, and 
SSLSetClientSideAuthenticate() is all about checking the client's 
certificate in the server, while libpq 'sslmode' is about checking the 
server's certificate in the client.


> +    for (;;)
> +    {
> +        status = SSLHandshake((SSLContextRef) port->ssl);
> +        if (status == noErr)
> +            break;
> +
> +        if (status == errSSLWouldBlock)
> +            continue;
> +        ...
> +    }

Does this busy-wait, if there's not enough data from the client? That 
seems bad. In the corresponding client-side code, there's a comment on 
that too, but it's still bad.

In be_tls_get_version and PQsslAttribute, can we add support for 
kTLSProtocol13? Perhaps with an autoconf test, if the constant is not 
available on all macOS versions.

In be_tls_get_peerdn_name, wouldn't SecCertificateCopyCommonName() be 
more appropriate than SecCertificateCopyLongDescription()?

In be_tls_get_cipher, returning "unknown" would seem better than 
erroring out, if the cipher isn't recognized.

Check error message style. eg.:

> +            ereport(COMMERROR,
> +                    (errmsg("could not load server certificate \"%s\": \"%s\"",
> +                            ssl_cert_file, pg_SSLerrmessage(status))));
> 

Why is the result of pg_SSLerrmessage() in quotes? Maybe errdetail?

> + * Any consumers of the Keychain array should always call this to ensure that
> + * it is set up in a manner that reflect the configuration. If it not, then

s/reflect/reflects/

> +    else if (keychain_count == 2)
> +    {
> +        if (ssl_keychain_file[0] == '\0' || !ssl_keychain_use_default)
> +            goto error;
> +
> +        return;
> +    }
> +    else
> +        /* Fallthrough to erroring out */
> +
> +error:
> +    ereport(FATAL,
> +            (errmsg("Incorrect loading of Keychains detected")));
> +}

That fallthrough looks dangerous.


> --- a/src/backend/utils/misc/postgresql.conf.sample
> +++ b/src/backend/utils/misc/postgresql.conf.sample
> @@ -106,6 +106,7 @@
>  #ssl_dh_params_file = ''
>  #ssl_passphrase_command = ''
>  #ssl_passphrase_command_supports_reload = off
> +#ssl_keychain_file = ''

Do we want to have this Secure Transport-specific option in the sample 
config file? Comment at least


> +#elif USE_SECURETRANSPORT
> +    void       *ssl;
> +    int            ssl_buffered;

Add comments. Mention the actual type of 'ssl' (SSLContextRef), and what 
'ssl_buffered' means.

libpq-be.h and libpq-int.h use a different strategy to avoid clashes 
between PostgreSQL's and Secure Transport's versions of Size and uint64. 
Let's be consistent. (I like the libpq-fe.h version more, i.e. using 
"void *" and avoiding the #include)

> - * SSL implementation (e.g. be-secure-openssl.c)
> + * SSL implementation (e.g. be-secure-<implementation>.c)

Since this is just an example, I think leaving it as be-secure-openssl.c 
is fine.

Also update pg_config.h.win32 with the new USE_SECURETRANSPOT flag being 
added to pg_config.h.in.

In the call to SSLSetPeerDomainName(), should check return code.

> +                /*
> +                 * In sslmode "require" we accept some certificate verification
> +                 * failures when we don't have a rootcert since MITM protection
> +                 * isn't enforced. Check the reported failure and trust in case
> +                 * the cert is missing, self signed or expired/future.
> +                 */
> +                if (strcmp(conn->sslmode, "require") == 0 && !conn->st_rootcert)
> +                {

Not just "require", but "allow" as well, right?

freePGconn should free conn->keychain. Would be good to write a little 
test that opens & closes millions of connectins, to check for memory leaks.

> + * Queries the specified Keychain, or the default unless not defined, for a

"unless not defined" is a double-negative. I don't understand that 
sentence. (there are two copies of the same comment in the patch, in FE 
and BE. And the FE function is called "load_identity_keychain", but its 
comment says "import_identity_keychain" )

PQinitOpenSSL and PQinitSSL are inconsistent in whether to call 
pgtls_init_library(), when compiled with Secure Transport. 
pgtls_init_library() is a no-op, so it doesn't matter, but let's be 
consistent. Perhaps do "#define pgtls_init_library() ((void)true)" in 
the header?

s/readiblitity/readability/
s/dont/don't/
s/securetransport_common.h/securetransport.h/
s/f.e/for example/ (at least I'm not familiar with that abbreviation)

--- end of laundry list ---

- Heikki


pgsql-hackers by date:

Previous
From: Dean Rasheed
Date:
Subject: Re: PG 10: could not generate random cancel key
Next
From: Grigory Smolkin
Date:
Subject: Another fun fact about temp tables and wraparound