Thread: contrib/pgcrypto functions not IMMUTABLE?

contrib/pgcrypto functions not IMMUTABLE?

From
Michael Fuhr
Date:
I've noticed that contrib/pgcrypto/pgcrypto.sql.in doesn't include
a volatility category in its CREATE FUNCTION statements, so the
functions are all created VOLATILE.  Shouldn't most of them be
IMMUTABLE?  Or do the algorithms have side effects?  So far I've
found no discussion about this except for one person asking about
it last year:

http://archives.postgresql.org/pgsql-admin/2004-12/msg00065.php

-- 
Michael Fuhr
http://www.fuhr.org/~mfuhr/


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Russell Smith
Date:
On Sun, 3 Jul 2005 03:32 pm, Michael Fuhr wrote:
> I've noticed that contrib/pgcrypto/pgcrypto.sql.in doesn't include
> a volatility category in its CREATE FUNCTION statements, so the
> functions are all created VOLATILE.  Shouldn't most of them be
> IMMUTABLE?  Or do the algorithms have side effects?  So far I've
> found no discussion about this except for one person asking about
> it last year:
> 
> http://archives.postgresql.org/pgsql-admin/2004-12/msg00065.php
> 
I know the salt functions MUST stay volatile, as they produce different output
every time you call them.  I've not looked at the pgcrypto code, so I can't
make further comment than that.

Regards

Russell Smith.


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Michael Fuhr
Date:
On Sun, Jul 03, 2005 at 04:24:31PM +1000, Russell Smith wrote:
> On Sun, 3 Jul 2005 03:32 pm, Michael Fuhr wrote:
> > I've noticed that contrib/pgcrypto/pgcrypto.sql.in doesn't include
> > a volatility category in its CREATE FUNCTION statements, so the
> > functions are all created VOLATILE.  Shouldn't most of them be
> > IMMUTABLE?  Or do the algorithms have side effects?
>
> I know the salt functions MUST stay volatile, as they produce different output
> every time you call them.  I've not looked at the pgcrypto code, so I can't
> make further comment than that.

Yeah, I see that gen_salt() needs to be volatile, but I was thinking
about functions like digest(), encrypt(), decrypt(), etc., that
would be expected to return the same output given the same input.
For example, the core md5() function is immutable, but pgcrypto's
digest() is volatile.  I was wondering if that's intentional or
just an oversight.

-- 
Michael Fuhr
http://www.fuhr.org/~mfuhr/


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Marko Kreen
Date:
On Sun, Jul 03, 2005 at 12:43:32AM -0600, Michael Fuhr wrote:
> On Sun, Jul 03, 2005 at 04:24:31PM +1000, Russell Smith wrote:
> > On Sun, 3 Jul 2005 03:32 pm, Michael Fuhr wrote:
> > > I've noticed that contrib/pgcrypto/pgcrypto.sql.in doesn't include
> > > a volatility category in its CREATE FUNCTION statements, so the
> > > functions are all created VOLATILE.  Shouldn't most of them be
> > > IMMUTABLE?  Or do the algorithms have side effects?
> >
> > I know the salt functions MUST stay volatile, as they produce different output
> > every time you call them.  I've not looked at the pgcrypto code, so I can't
> > make further comment than that.
> 
> Yeah, I see that gen_salt() needs to be volatile, but I was thinking
> about functions like digest(), encrypt(), decrypt(), etc., that
> would be expected to return the same output given the same input.
> For example, the core md5() function is immutable, but pgcrypto's
> digest() is volatile.  I was wondering if that's intentional or
> just an oversight.

Just an oversight.

Could you send a patch to -patches that fixes it?  It would take
some time to do it myself, as I am coding an additional feature
to the PGP functions, and all my free time goes to that.

And if you decide to do it, please make them all STRICT too,
_except_ encrypt/decrypt functions.  Thats an additional change
I have in the air for pgcrypto.sql.in.

As for the encrypt/decrypt functions, I am increasingly
favouring throwing error in case of NULL arguments.  I'm fearing
a scenario, where somebody sets a encrypted data field to NULL,
and the change goes undetected.  This may not be that relevant
for encrypt/decrypt as their integrity protection is almost
non-existant, but is very relevant for PGP functions, as
they offer very strong guarantees.

Does anybody see a scenario, where this would be unreasonable?

-- 
marko



Re: contrib/pgcrypto functions not IMMUTABLE?

From
Michael Fuhr
Date:
On Sun, Jul 03, 2005 at 03:59:51PM +0300, Marko Kreen wrote:
> On Sun, Jul 03, 2005 at 12:43:32AM -0600, Michael Fuhr wrote:
> > 
> > Yeah, I see that gen_salt() needs to be volatile, but I was thinking
> > about functions like digest(), encrypt(), decrypt(), etc., that
> > would be expected to return the same output given the same input.
> > For example, the core md5() function is immutable, but pgcrypto's
> > digest() is volatile.  I was wondering if that's intentional or
> > just an oversight.
> 
> Just an oversight.
> 
> Could you send a patch to -patches that fixes it?  It would take
> some time to do it myself, as I am coding an additional feature
> to the PGP functions, and all my free time goes to that.
> 
> And if you decide to do it, please make them all STRICT too,
> _except_ encrypt/decrypt functions.  Thats an additional change
> I have in the air for pgcrypto.sql.in.

I'll submit a patch.  Does the following look right?

digest         IMMUTABLE STRICT
digest_exists  IMMUTABLE STRICT
hmac           IMMUTABLE STRICT
hmac_exists    IMMUTABLE STRICT
crypt          IMMUTABLE STRICT
gen_salt       VOLATILE STRICT
encrypt        IMMUTABLE
decrypt        IMMUTABLE
encrypt_iv     IMMUTABLE
decrypt_iv     IMMUTABLE
cipher_exists  IMMUTABLE STRICT

In the functions marked STRICT, should I leave the PG_ARGISNULL()
checks in place as a precaution?  Removing those checks could cause
problems if people use the new code but have old (non-STRICT) catalog
entries.

-- 
Michael Fuhr
http://www.fuhr.org/~mfuhr/


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Marko Kreen
Date:
On Sun, Jul 03, 2005 at 07:54:47AM -0600, Michael Fuhr wrote:
> I'll submit a patch.  Does the following look right?
> 
> digest         IMMUTABLE STRICT
> digest_exists  IMMUTABLE STRICT
> hmac           IMMUTABLE STRICT
> hmac_exists    IMMUTABLE STRICT
> crypt          IMMUTABLE STRICT
> gen_salt       VOLATILE STRICT
> encrypt        IMMUTABLE
> decrypt        IMMUTABLE
> encrypt_iv     IMMUTABLE
> decrypt_iv     IMMUTABLE
> cipher_exists  IMMUTABLE STRICT

Nice overview.  Now that I have them before me, I think crypt() should
stay also non-strict, as it also has delicate security properties.

Everything else is OK.

> In the functions marked STRICT, should I leave the PG_ARGISNULL()
> checks in place as a precaution?  Removing those checks could cause
> problems if people use the new code but have old (non-STRICT) catalog
> entries.

Good point.  Let them be.

Rather, could you make crypt, encrypt, decrypt return error for
NULL input?  With nice message, eg. "NULL input"...

Then this topic would be solved in one go.

-- 
marko



Re: contrib/pgcrypto functions not IMMUTABLE?

From
Tom Lane
Date:
Marko Kreen <marko@l-t.ee> writes:
> And if you decide to do it, please make them all STRICT too,
> _except_ encrypt/decrypt functions.  Thats an additional change
> I have in the air for pgcrypto.sql.in.

> As for the encrypt/decrypt functions, I am increasingly
> favouring throwing error in case of NULL arguments.

That doesn't seem like a good idea at all.  Why shouldn't an encryptable
value be NULL?  I think you should just make 'em strict.
        regards, tom lane


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Marko Kreen
Date:
On Sun, Jul 03, 2005 at 12:02:38PM -0400, Tom Lane wrote:
> Marko Kreen <marko@l-t.ee> writes:
> > And if you decide to do it, please make them all STRICT too,
> > _except_ encrypt/decrypt functions.  Thats an additional change
> > I have in the air for pgcrypto.sql.in.
> 
> > As for the encrypt/decrypt functions, I am increasingly
> > favouring throwing error in case of NULL arguments.
> 
> That doesn't seem like a good idea at all.  Why shouldn't an encryptable
> value be NULL?  I think you should just make 'em strict.

Well, I have mainly issues with decrypt part.  I'd like
to say, if decrypt succeeds, whoever put the data there,
had the key.  Existing decrypt() has a smell of it - there
is 1/256 chance that data modification won't be detected.
With PGP, this is part of functionality - there will
be SHA1 attached to data.  Now, encrypt() should throw
error just for symmetricity and to force user handle the
'no data' case externally.

On the other hand, all this is corner-case protection
from someone who has already write-access to table.
This could be also solved with documenting that user must
specifically think how to handle 'success' from null values.

As for the crypt() case, lets say you have a new user with
hashed password field NULL.  In addition, you have client
program that compares crypt() result with hashed field
itself, in addition it handles NULL's as empty string.
Result: it is possible to login with any password.
Lots of assumptions but in eg. PHP case they are all filled.

Do you object to non-strict crypt() too?

-- 
marko



Re: contrib/pgcrypto functions not IMMUTABLE?

From
Tom Lane
Date:
Marko Kreen <marko@l-t.ee> writes:
> On Sun, Jul 03, 2005 at 12:02:38PM -0400, Tom Lane wrote:
>> That doesn't seem like a good idea at all.  Why shouldn't an encryptable
>> value be NULL?  I think you should just make 'em strict.

> Well, I have mainly issues with decrypt part.  I'd like
> to say, if decrypt succeeds, whoever put the data there,
> had the key.  Existing decrypt() has a smell of it - there
> is 1/256 chance that data modification won't be detected.

And that has what to do with throwing an error on NULL input?

> As for the crypt() case, lets say you have a new user with
> hashed password field NULL.  In addition, you have client
> program that compares crypt() result with hashed field
> itself, in addition it handles NULL's as empty string.
> Result: it is possible to login with any password.
> Lots of assumptions but in eg. PHP case they are all filled.

A NULL password field is intended to have exactly that effect, no?
        regards, tom lane


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Marko Kreen
Date:
On Sun, Jul 03, 2005 at 12:57:54PM -0400, Tom Lane wrote:
> Marko Kreen <marko@l-t.ee> writes:
> > On Sun, Jul 03, 2005 at 12:02:38PM -0400, Tom Lane wrote:
> >> That doesn't seem like a good idea at all.  Why shouldn't an encryptable
> >> value be NULL?  I think you should just make 'em strict.
> 
> > Well, I have mainly issues with decrypt part.  I'd like
> > to say, if decrypt succeeds, whoever put the data there,
> > had the key.  Existing decrypt() has a smell of it - there
> > is 1/256 chance that data modification won't be detected.
> 
> And that has what to do with throwing an error on NULL input?

It is not an encrypted value so do not succeed.

> > As for the crypt() case, lets say you have a new user with
> > hashed password field NULL.  In addition, you have client
> > program that compares crypt() result with hashed field
> > itself, in addition it handles NULL's as empty string.
> > Result: it is possible to login with any password.
> > Lots of assumptions but in eg. PHP case they are all filled.
> 
> A NULL password field is intended to have exactly that effect, no?

I hope not.

But I think I see - throwing error on NULL goes against standard
practice and anyway NULL handling should be user responsibility,
not pgcrypto's.

Maybe I'm getting too paranoid from tracking all the error
conditions in pgp code.

Michael, the result is, you can make them all STRICT.

-- 
marko



Re: contrib/pgcrypto functions not IMMUTABLE?

From
Alvaro Herrera
Date:
On Sun, Jul 03, 2005 at 12:57:54PM -0400, Tom Lane wrote:
> Marko Kreen <marko@l-t.ee> writes:

> > As for the crypt() case, lets say you have a new user with
> > hashed password field NULL.  In addition, you have client
> > program that compares crypt() result with hashed field
> > itself, in addition it handles NULL's as empty string.
> > Result: it is possible to login with any password.
> > Lots of assumptions but in eg. PHP case they are all filled.
> 
> A NULL password field is intended to have exactly that effect, no?

Not necessarily -- it may mean the user was just created, or it was
"deactivated" by setting the password to NULL.  Yes, this last thing is
foolish, but people do it anyway ...

-- 
Alvaro Herrera (<alvherre[a]surnet.cl>)
"The only difference is that Saddam would kill you on private, where the
Americans will kill you in public" (Mohammad Saleh, 39, a building contractor)


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Tom Lane
Date:
Alvaro Herrera <alvherre@surnet.cl> writes:
>> Marko Kreen <marko@l-t.ee> writes:
>>> As for the crypt() case, lets say you have a new user with
>>> hashed password field NULL.  In addition, you have client
>>> program that compares crypt() result with hashed field
>>> itself, in addition it handles NULL's as empty string.
>>> Result: it is possible to login with any password.
>>> Lots of assumptions but in eg. PHP case they are all filled.
>> 
>> A NULL password field is intended to have exactly that effect, no?

> Not necessarily -- it may mean the user was just created, or it was
> "deactivated" by setting the password to NULL.  Yes, this last thing is
> foolish, but people do it anyway ...

Nonetheless, I have a problem with allowing this one scenario to drive a
bizarre design of the function.  For every user that is able to omit an
explicit NULL test in this case, there will be ten that have to add one
to avoid their apps blowing up because the function errors out on NULLs.
Just because it's security-related doesn't mean you shouldn't follow the
principle of least surprise and make this SQL function act like 99% of
other SQL functions do when handed a NULL.

And if crypt() should act this way, why not also md5() for instance?
        regards, tom lane


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Neil Conway
Date:
Marko Kreen wrote:
> On Sun, Jul 03, 2005 at 07:54:47AM -0600, Michael Fuhr wrote:
>>In the functions marked STRICT, should I leave the PG_ARGISNULL()
>>checks in place as a precaution?  Removing those checks could cause
>>problems if people use the new code but have old (non-STRICT) catalog
>>entries.
> 
> Good point.  Let them be.

Assuming the STRICT / IMMUTABLE changes are only going into HEAD, you 
can safely remove the PG_ARGISNULL() checks -- people upgrading from a 
prior version of Postgres (and therefore pgcrypto) will need to dump and 
reload anyway.

-Neil


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Michael Fuhr
Date:
On Mon, Jul 04, 2005 at 11:42:14AM +1000, Neil Conway wrote:
> 
> Assuming the STRICT / IMMUTABLE changes are only going into HEAD, you 
> can safely remove the PG_ARGISNULL() checks -- people upgrading from a 
> prior version of Postgres (and therefore pgcrypto) will need to dump and 
> reload anyway.

But if they restore a dump made with pg_dump or pg_dumpall, they'll
get the old catalog entries sans STRICT, no?  People might rebuild
the module when they upgrade, but they might not think to drop and
recreate the functions since the definitions are already in the
dump.  I suppose the Release Notes could mention that recreating
the functions is required; it could also show the SQL statements
necessary to update pg_proc so a drop/recreate wouldn't be necessary.

-- 
Michael Fuhr
http://www.fuhr.org/~mfuhr/


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Neil Conway
Date:
Michael Fuhr wrote:
> But if they restore a dump made with pg_dump or pg_dumpall, they'll
> get the old catalog entries sans STRICT, no?  People might rebuild
> the module when they upgrade, but they might not think to drop and
> recreate the functions since the definitions are already in the
> dump.

I think it is asking for trouble in general to use the DDL from one 
version of pgcrypto with a different version of the pgcrypto 
implementation. However, you're right that people are inevitably going 
to do this, so I suppose we need to keep the checks. Perhaps it would be 
worth adding something to the installation documentation suggesting that 
people take care when installing new versions of contrib/ packages and 
the like without updating the DDL for those packages.

-Neil


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Michael Fuhr
Date:
On Sun, Jul 03, 2005 at 08:15:07PM +0300, Marko Kreen wrote:
> 
> Michael, the result is, you can make them all STRICT.

OK.  Does anybody else have thoughts on removing the PG_ARGISNULL()
checks?  Neil suggests removing them because they'd be unnecessary,
but I'm concerned about people who'd use the new code with old
catalog entries that aren't STRICT (e.g., restored from a dump).
Should we leave the PG_ARGISNULL() checks in place as a safety
measure, or should the 8.1 Release Notes make it clear that the
functions need to be recreated (or pg_proc updated)?

-- 
Michael Fuhr
http://www.fuhr.org/~mfuhr/


Re: contrib/pgcrypto functions not IMMUTABLE?

From
Tom Lane
Date:
Michael Fuhr <mike@fuhr.org> writes:
> OK.  Does anybody else have thoughts on removing the PG_ARGISNULL()
> checks?  Neil suggests removing them because they'd be unnecessary,
> but I'm concerned about people who'd use the new code with old
> catalog entries that aren't STRICT (e.g., restored from a dump).

I concur with leaving them in for awhile.  They aren't all that
expensive ...
        regards, tom lane