Re: Random number generation, take two

From: Heikki Linnakangas <hlinnaka(at)iki(dot)fi>
To: Michael Paquier <michael(dot)paquier(at)gmail(dot)com>
Cc: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Random number generation, take two
Date: 2016-11-30 11:51:27
Message-ID: 4dc2cc3f-3534-d287-2985-e9c2b7ff2231@iki.fi
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 11/30/2016 09:01 AM, Michael Paquier wrote:
> On Tue, Nov 29, 2016 at 10:02 PM, Heikki Linnakangas <hlinnaka(at)iki(dot)fi> wrote:
>> Phew, this has been way more complicated than it seemed at first. Thoughts?
>
> One of the goals of this patch is to be able to have a strong random
> function as well for the frontend, which is fine. But any build where
> --disable-strong-random is used is not going to have a random function
> to rely on. Disabling SCRAM for such builds is a possibility, because
> we assume that any build using --disable-strong-random is aware of
> security risks, still that's not really appealing in terms of
> portability. Another possibility would be to have an extra routine
> like pg_frontend_random(), wrapping pg_strong_backend() and using a
> combination of getpid + gettimeofday to generate a seed with just a
> random() call? That's what we were fighting against previously, so my
> mind is telling me that just returning an error when the code paths of
> the SCRAM client code is used when built with --disable-strong-random
> is the way to go, because we want SCRAM to be fundamentally safe to
> use. What do you think?

I was thinking that with --disable-strong-random, we'd use plain
random() in libpq as well. I believe SCRAM is analogous to the MD5 salt
generation in the backend, in its requirement for randomness. The SCRAM
spec (RFC5802) says:

> It is important that this value [nonce] be different for each
> authentication (see [RFC4086] for more details on how to achieve
> this)

So the nonces need to be different for each session, to avoid replay
attacks. But they don't necessarily need to be unpredictable, they are
transmitted in plaintext during the authentication, anyway. If an
attacker can calculate them in advance, it only buys him more time, but
doesn't give any new information.

If we were 100% confident on that point, we could just always use
current timestamp and a counter for the nonces. But I'm not that
confident, certainly feels better to use a stronger random number when
available. The quote above points at RFC4086, which actually talks about
cryptographically strong random numbers, rather than just generating a
unique nonce. So I'm not sure if the authors of SCRAM considered that
point in any detail, seems like they just assumed that you might as well
use a strong random source because everyone's got one.

>> pgcrypto
>> --------
>>
>> pgcrypto doesn't have the same requirements for "strongness" as cancel keys
>> and MD5 salts have. pgcrypto uses random numbers for generating salts, too,
>> which I think has similar requirements. But it also uses random numbers for
>> generating encryption keys, which I believe ought to be harder to predict.
>> If you compile with --disable-strong-random, do we want the encryption key
>> generation routines to fail, or to return known-weak keys?
>>
>> This patch removes the Fortuna algorithm, that was used to generate fairly
>> strong random numbers, if OpenSSL was not present. One option would be to
>> keep that code as a fallback. I wanted to get rid of that, since it's only
>> used on a few old platforms, but OTOH it's been around for a long time with
>> little issues.
>>
>> As this patch stands, it removes Fortuna, and returns known-weak keys, but
>> there's a good argument to be made for throwing an error instead.
>
> IMO, leading to an error would make the users aware of them playing
> with the fire... Now pademelon's owner may likely have a different
> opinion on the matter :p

Ok, I bit the bullet and modified those pgcrypto functions that truly
need cryptographically strong random numbers to throw an error with
--disable-strong-random. Notably, the pgp encrypt functions mostly fail now.

> Documentation for --disable-strong-random needs to be added.

Ah, I didn't remember we have a section in the user manual for these. Added.

> + int32 MyCancelKey;
> Those would be better as unsigned?

Perhaps, but it's historically been signed, I'm afraid of changing it..

> +bool
> +pg_backend_random(char *dst, int len)
> +{
> + int i;
> + char *end = dst + len;
> +
> + /* should not be called in postmaster */
> + Assert (IsUnderPostmaster || !IsPostmasterEnvironment);
> +
> + LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE);
> Shouldn't an exclusive lock be taken only when the initialization
> phase is called? When reading the value a shared lock would be fine.

No, it needs to be exclusive. Each pg_jrand48() call updates the state,
aka seed.

> Attached is a patch for MSVC to apply on top of yours to enable the
> build for strong and weak random functions. Feel free to hack it as
> needs be, this base implementation works for the current
> implementation.

Great, thanks! I wonder if this is overly complicated, though. For
comparison, we haven't bothered to expose --disable-spinlocks in
config_default.pl either. Perhaps we should just always use the Windows
native function on MSVC, whether or not configured with OpenSSL, and
just put USE_WIN32_RANDOM in pg_config.h.win32? See 2nd attached patch
(untested).

- Heikki

Attachment Content-Type Size
0001-Replace-PostmasterRandom-with-a-stronger-source-seco.patch.gz application/gzip 26.8 KB
0002-Fix-MSVC-build.patch application/x-download 1.7 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Alvaro Herrera 2016-11-30 12:38:04 Re: patch: function xmltable
Previous Message Simon Riggs 2016-11-30 11:50:12 Re: XactLockTableWait doesn't set wait_event correctly