Re: Negotiating the SCRAM channel binding type

From: Heikki Linnakangas <hlinnaka(at)iki(dot)fi>
To: Michael Paquier <michael(at)paquier(dot)xyz>
Cc: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Negotiating the SCRAM channel binding type
Date: 2018-08-05 11:00:04
Message-ID: 6ada9d4a-0067-d290-6f9d-14b2a8fac0a0@iki.fi
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Thanks for the review!

On 22/07/18 16:54, Michael Paquier wrote:
> On Fri, Jul 20, 2018 at 08:05:04PM +0300, Heikki Linnakangas wrote:
>> This removes the scram_channel_binding libpq option altogether, since there
>> is now only one supported channel binding type.
>
> This can also be used to switch off channel binding on the client-side,
> which is the behavior you could get only by using a version of libpq
> compiled with v10 in the context of an SSL connection. Do we really
> want to lose this switch as well? I like feature switches.

Well, it'd be useless for users, there is no reason to switch off
channel binding if both the client and server support it. It might not
add any security you care about, but it won't do any harm either. The
non-channel-binding codepath is still exercised with non-SSL connections.

> +PostgreSQL is <literal>tls-server-end-point</literal>. If other channel
> +binding types are supported in the future, the server will advertise
> +them as separate SASL mechanisms.
> I don't think that this is actually true, per my remark of upthread we
> could also use an option-based approach with each SASL mechanism sent by
> the server. I would recommend to remove this last sentence.

Ok. That's how I'm envisioning we'd add future binding types, but since
we're not sure, I'll leave it out.

> + man-in-the-middle attacks by mixing the signature of the server's
> + certificate into the transmitted password hash. While a fake server can
> + retransmit the real server's certificate, it doesn't have access to the
> + private key matching that certificate, and therefore cannot prove it is
> + the owner, causing SSL connection failure
> Nit: insisting on the fact that tls-server-end-point is used in this
> context.

Yeah, that's the assumption. Now that we only do tls-server-end-point, I
think we can assume that without further explanation.

> +void
> +pg_be_scram_get_mechanisms(Port *port, StringInfo buf)
> +{
> + /*
> + * Advertise the mechanisms in decreasing order of importance. So the
> + * channel-binding variants go first, if they are supported. Channel
> + * binding is only supported with SSL, and only if the SSL implementation
> + * has a function to get the certificate's hash
> [...]
> +#ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
> + if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use)
> + state->channel_binding_in_use = true;
> + else
> +#endif
> Hm. I think that this should be part of the set of APIs that each SSL
> implementation has to provide. It is not clear to me yet if using the
> flavor of SSL in Windows or macos universe will allow end-point to work,
> and this could make this proposal more complicated. And
> HAVE_BE_TLS_GET_CERTIFICATE_HASH is something OpenSSL-ish, so I would
> recommend to remove all SSL-implementation-specific code from auth*.c
> and fe-auth*.c, keeping those in their own file. One simple way to
> address this problem would be to make each SSL implementation return a
> boolean to tell if it supports SCRAM channel binding or not, with Port*
> of PGconn* in input to be able to filter connections using SSL or not.

The idea here is that if the SSL implementation implements the required
functions, it #defines HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH (in the
client) and/or HAVE_BE_TLS_GET_CERTIFICATE_HASH (in the server). So the
code above is not implementation-specific; it doesn't know the details
of OpenSSL, it only refers to the compile-time flag which the SSL
implementation-specific code defines. The flag is part of the API that
the SSL implementation provides, it's just a compile-time flag rather
than run-time.

I'll try to clarify the comments on this.

> + if (strcmp(channel_binding_type, "tls-server-end-point") != 0)
> + ereport(ERROR,
> + (errcode(ERRCODE_PROTOCOL_VIOLATION),
> + (errmsg("unsupported SCRAM channel-binding type
> \"%s\"",
> + sanitize_str(channel_binding_type)))));
> Let's give up on sanitize_str. I am not sure that it is a good idea to
> print in error messages server-side something that the client has sent.

Well, the point of sanitize_str is to make it safe. You're right that
it's not strictly necessary, but I think it would be helpful to print
out the channel binding type that the client attempted to use.

> And a couple of lines down the call to be_tls_get_certificate_hash in
> auth-scram.c is only protected by USE_SSL... So compilation would
> likely break once a new SSL implementation is added, and libpq-be.h gets
> uglier.

Fixed by changing "#ifdef USE_SSL" to "#ifdef
HAVE_BE_TLS_GET_CERTIFICATE_HASH".

It's true that there is some risk for libpq-be.h (and libpq-int.h) to
become ugly, if we add more SSL implementations, and if those
implementations have complicated conditions on whether they can get the
certificate hashes. In practice, I think it's going to be OK. All the
SSL implementations we've talked about - GnuTLS, macOS, Windows - do
support the functionality, so we don't need complicated #ifdefs in the
header. But we can revisit this if it gets messy.

I did some further testing with this, compiling with and without
HAVE_BE_TLS_GET_CERTIFICATE_HASH and
HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH, and fixed a few combinations that
did not work. And I fixed the other comment typos etc. that you pointed out.

I have committed this now, because I think it's important to get this
into the next beta version, and I'd like to get a full cycle on the
buildfarm before that. But if you have the chance, please have one more
look at the committed version, to make sure I didn't mess something up.

- Heikki

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Heikki Linnakangas 2018-08-05 11:18:59 Re: GiST VACUUM
Previous Message Andres Freund 2018-08-05 10:19:09 Re: TupleTableSlot abstraction