SCRAM authentication, take three
I rebased the SCRAM authentication patches over current master. Here you
are.
I'm trying to whack this into the final shape that it could actually be
committed. The previous thread on SCRAM authentication has grown
ridiculously long and meandered into all kinds of details, so I thought
it's best to start afresh with a new thread.
So, if you haven't paid attention on this for a while, now would be a
good time to have another look at the patch. I believe all the basic
functionality, documentation, and tests are there, and there are no
known bugs. Please review! I'll start reading through these myself again
tomorrow.
One thing that's missing, that we need to address before the release, is
the use of SASLPrep to "normalize" the password. We discussed that in
the previous thread, and I think we have a good path forward on it. I'd
be happy to leave that for a follow-up commit, after these other patches
have been committed, so we can discuss that work separately.
These are also available on Michael's github repository, at
https://github.com/michaelpq/postgres/tree/scram.
- Heikki
Attachments:
Hello.
Good to know that the work on this great feature continues!
However this set of patches does not pass `make check-world` on my
laptop.
Here is how I build and test PostgreSQL:
https://github.com/afiskon/pgscripts/blob/master/full-build.sh
Error message:
http://afiskon.ru/s/0b/258c6e4f14_123.txt
regression.diffs:
http://afiskon.ru/s/a0/4993102c32_regression.diffs.txt
regression.out:
http://afiskon.ru/s/4b/acd5a58374_regression.out.txt
Backtrace:
http://afiskon.ru/s/00/c0b32b45a6_bt.txt
I'm using Arch Linux with latest updates, Python version is 3.6.0. I
have no idea what SCRAM has to do with Python, but this issue reproduced
two times of two I did `make check-world`. There is no such issue in
current master branch.
On Mon, Feb 06, 2017 at 02:55:08PM +0200, Heikki Linnakangas wrote:
I rebased the SCRAM authentication patches over current master. Here you
are.I'm trying to whack this into the final shape that it could actually be
committed. The previous thread on SCRAM authentication has grown
ridiculously long and meandered into all kinds of details, so I thought it's
best to start afresh with a new thread.So, if you haven't paid attention on this for a while, now would be a good
time to have another look at the patch. I believe all the basic
functionality, documentation, and tests are there, and there are no known
bugs. Please review! I'll start reading through these myself again tomorrow.One thing that's missing, that we need to address before the release, is the
use of SASLPrep to "normalize" the password. We discussed that in the
previous thread, and I think we have a good path forward on it. I'd be happy
to leave that for a follow-up commit, after these other patches have been
committed, so we can discuss that work separately.These are also available on Michael's github repository, at
https://github.com/michaelpq/postgres/tree/scram.- Heikki
--
Best regards,
Aleksander Alekseev
Aleksander Alekseev wrote:
Hello.
Good to know that the work on this great feature continues!
However this set of patches does not pass `make check-world` on my
laptop.Here is how I build and test PostgreSQL:
https://github.com/afiskon/pgscripts/blob/master/full-build.sh
I think you need "make distclean" instead of "make clean", unless you
also add --enable-depend to configure.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
No, I'm afraid `make distclean` doesn't help. I've re-checked twice.
On Mon, Feb 06, 2017 at 12:52:11PM -0300, Alvaro Herrera wrote:
Aleksander Alekseev wrote:
Hello.
Good to know that the work on this great feature continues!
However this set of patches does not pass `make check-world` on my
laptop.Here is how I build and test PostgreSQL:
https://github.com/afiskon/pgscripts/blob/master/full-build.sh
I think you need "make distclean" instead of "make clean", unless you
also add --enable-depend to configure.--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Best regards,
Aleksander Alekseev
On Tue, Feb 7, 2017 at 3:12 AM, Aleksander Alekseev
<a.alekseev@postgrespro.ru> wrote:
No, I'm afraid `make distclean` doesn't help. I've re-checked twice.
Hm. I can see the failure on macos and python2 builds as well with the
set of patches applied. And the master branch is working properly.
This needs some investigation.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Feb 6, 2017 at 9:55 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I rebased the SCRAM authentication patches over current master. Here you
are.
Thanks! Nice to see you around.
So, if you haven't paid attention on this for a while, now would be a good
time to have another look at the patch. I believe all the basic
functionality, documentation, and tests are there, and there are no known
bugs. Please review! I'll start reading through these myself again tomorrow.
To all: this wiki page is up to date with all the items that remain:
https://wiki.postgresql.org/wiki/SCRAM_authentication
I am keeping the list there up to date with issues noticed on the way.
One thing that's missing, that we need to address before the release, is the
use of SASLPrep to "normalize" the password. We discussed that in the
previous thread, and I think we have a good path forward on it. I'd be happy
to leave that for a follow-up commit, after these other patches have been
committed, so we can discuss that work separately.
Yes, I am actively working on this one now. I am trying to come up
first with something in the shape of an extension to begin with, and
get a patch out of it. That will be more simple for testing. For now
the work that really remains in the patches attached on this thread is
to get the internal work done, all the UTF8-related routines being
already present in scram-common.c to work on the strings.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Feb 7, 2017 at 11:28 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
Yes, I am actively working on this one now. I am trying to come up
first with something in the shape of an extension to begin with, and
get a patch out of it. That will be more simple for testing. For now
the work that really remains in the patches attached on this thread is
to get the internal work done, all the UTF8-related routines being
already present in scram-common.c to work on the strings.
It took me a couple of days... And attached is the prototype
implementing SASLprep(), or NFKC if you want for UTF-8 strings. This
extension is pretty useful to check the validity of any normalization
forms defined in the Unicode specs, and is as well on my github:
https://github.com/michaelpq/pg_plugins/tree/master/pg_sasl_prepare
In short, at build what this extension does is fetching
UnicodeData.txt, and it builds a conversion table including the fields
necessary for NFKC:
- The utf code of a character.
- The combining class of the character.
- The decomposition sets of characters.
I am aware of the fact that the implemention of this extension is the
worst possible, there are many bytes wasted, and the resulting shared
library gets at 2.4MB. Now as an example of how normalization forms
work that's a great study, and with that I am now aware of what needs
to be done to reduce the size of the conversion tables.
This extension has two conversion functions for UTF-8 string <=>
integer array (as UTF-8 characters are on 4 bytes with pg_wchar):
=# SELECT array_to_utf8('{50064}');
array_to_utf8
---------------
Ð
(1 row)
=# SELECT utf8_to_array('ÐÐÐ');
utf8_to_array
---------------------
{50064,50064,50064}
(1 row)
Then using an integer array in input SASLprep() can be done using
pg_sasl_prepare(), which returns to caller a decomposed recursively
set, with reordering done using the combining class integer array from
the conversion table generated wiht UnicodeData.txt. Lookups at the
conversion tables are done using bsearch(), so that's, at least I
guess, fast.
I have implemented as well a function to query the whole conversion as
a SRF (character number, combining class and decomposition), which is
useful for analysis:
=# select count(*) from utf8_conv_table();
count
-------
30590
(1 row)
Now using this module I have arrived to the following conclusions to
put to a minimum the size of the conversion tables, without much
impacting lookup performance:
- There are 24k characters with a combining class of 0 and no
decomposition for a total of 30k characters, those need to be dropped
from the conversion table.
- Most characters have a single, or double decomposition, one has a
decomposition of 18 characters. So we need to create two sets of
conversion tables:
-- A base table, with the character number (4 bytes), the combining
class (1 byte) and the size of the decomposition (1 byte).
-- A set of decomposition tables, classified by size.
So when decomposing a character, we check first the size of the
decomposition, then get the set from the correct table.
Now regarding the shape of the implementation for SCRAM, we need one
thing: a set of routines in src/common/ to build decompositions for a
given UTF-8 string with conversion UTF8 string <=> pg_wchar array, the
decomposition and the reordering. The extension attached roughly
implements that. What we can actually do as well is have in contrib/ a
module that does NFK[C|D] using the base APIs in src/common/. Using
arrays of pg_wchar (integers) to manipulate the characters, we can
validate and have a set of regression tests that do *not* have to
print non-ASCII characters. Let me know if this plan looks good, now I
think that I have enough material to get SASLprep done cleanly, with a
minimum memory footprint.
Heikki, others, how does that sound for you?
--
Michael
Attachments:
On 02/09/2017 09:33 AM, Michael Paquier wrote:
On Tue, Feb 7, 2017 at 11:28 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:Yes, I am actively working on this one now. I am trying to come up
first with something in the shape of an extension to begin with, and
get a patch out of it. That will be more simple for testing. For now
the work that really remains in the patches attached on this thread is
to get the internal work done, all the UTF8-related routines being
already present in scram-common.c to work on the strings.It took me a couple of days... And attached is the prototype
implementing SASLprep(), or NFKC if you want for UTF-8 strings.
Cool!
Now using this module I have arrived to the following conclusions to
put to a minimum the size of the conversion tables, without much
impacting lookup performance:
- There are 24k characters with a combining class of 0 and no
decomposition for a total of 30k characters, those need to be dropped
from the conversion table.
- Most characters have a single, or double decomposition, one has a
decomposition of 18 characters. So we need to create two sets of
conversion tables:
-- A base table, with the character number (4 bytes), the combining
class (1 byte) and the size of the decomposition (1 byte).
-- A set of decomposition tables, classified by size.
So when decomposing a character, we check first the size of the
decomposition, then get the set from the correct table.
Sounds good.
Now regarding the shape of the implementation for SCRAM, we need one
thing: a set of routines in src/common/ to build decompositions for a
given UTF-8 string with conversion UTF8 string <=> pg_wchar array, the
decomposition and the reordering. The extension attached roughly
implements that. What we can actually do as well is have in contrib/ a
module that does NFK[C|D] using the base APIs in src/common/. Using
arrays of pg_wchar (integers) to manipulate the characters, we can
validate and have a set of regression tests that do *not* have to
print non-ASCII characters.
A contrib module or built-in extra functions to deal with Unicode
characters might be handy for a lot of things. But I'd leave that out
for now, to keep this patch minimal.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 02/07/2017 04:20 AM, Michael Paquier wrote:
On Tue, Feb 7, 2017 at 3:12 AM, Aleksander Alekseev
<a.alekseev@postgrespro.ru> wrote:No, I'm afraid `make distclean` doesn't help. I've re-checked twice.
Hm. I can see the failure on macos and python2 builds as well with the
set of patches applied. And the master branch is working properly.
This needs some investigation.
Ah, found it. It was because of this change:
--- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -247,6 +247,7 @@ Section: Class 28 - Invalid Authorization Specification28000 E ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION invalid_authorization_specification
28P01 E ERRCODE_INVALID_PASSWORD invalid_password
+28P01 E ERRCODE_INVALID_NONCE invalid_nonce
Having two error codes with the same SQLSTATE is not cool, and tripped
the assertion in PL/python. I removed the new error code, it was only
used in one place, and ERRCODE_PROTOCOL_VIOLATIOn was more appropriate
there anyway.
Attached is a new set of patches, with that fixed. Thanks for the report
Aleksander!
- Heikki
Attachments:
On Wed, Feb 15, 2017 at 7:58 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 02/09/2017 09:33 AM, Michael Paquier wrote:
Now regarding the shape of the implementation for SCRAM, we need one
thing: a set of routines in src/common/ to build decompositions for a
given UTF-8 string with conversion UTF8 string <=> pg_wchar array, the
decomposition and the reordering. The extension attached roughly
implements that. What we can actually do as well is have in contrib/ a
module that does NFK[C|D] using the base APIs in src/common/. Using
arrays of pg_wchar (integers) to manipulate the characters, we can
validate and have a set of regression tests that do *not* have to
print non-ASCII characters.A contrib module or built-in extra functions to deal with Unicode characters
might be handy for a lot of things. But I'd leave that out for now, to keep
this patch minimal.
No problem from me. I'll get something for SASLprep in the shape of
something like the above. It should not take me long.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Feb 15, 2017 at 8:28 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
Ah, found it. It was because of this change:
Having two error codes with the same SQLSTATE is not cool, and tripped the
assertion in PL/python. I removed the new error code, it was only used in
one place, and ERRCODE_PROTOCOL_VIOLATIOn was more appropriate there anyway.
It seems that this one is on me. Thanks for looking at it.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Feb 15, 2017 at 9:27 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Wed, Feb 15, 2017 at 7:58 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 02/09/2017 09:33 AM, Michael Paquier wrote:
Now regarding the shape of the implementation for SCRAM, we need one
thing: a set of routines in src/common/ to build decompositions for a
given UTF-8 string with conversion UTF8 string <=> pg_wchar array, the
decomposition and the reordering. The extension attached roughly
implements that. What we can actually do as well is have in contrib/ a
module that does NFK[C|D] using the base APIs in src/common/. Using
arrays of pg_wchar (integers) to manipulate the characters, we can
validate and have a set of regression tests that do *not* have to
print non-ASCII characters.A contrib module or built-in extra functions to deal with Unicode characters
might be handy for a lot of things. But I'd leave that out for now, to keep
this patch minimal.No problem from me. I'll get something for SASLprep in the shape of
something like the above. It should not take me long.
OK, attached is a patch that implements SASLprep that needs to be
applied on top of the other ones. When working on the table reduction,
the worst size was at 2.4MB. After removing all the characters with a
class of 0 and no decomposition, I am able to get that down to 570kB.
After splitting the decompositions by size into their own tables, it
got down to 120kB, which is even nicer. One thing that I forgot
previously was the handling of the decomposition of Hangul characters
(Korean stuff) which is algorithmic, so you actually do not need a
table for them. The algorithm is here for the curious =>
http://unicode.org/reports/tr15/tr15-18.html#Hangul.
The patch includes the conversion tables, which is why it is large,
and the perl script that I used to generate it. It has been pushed as
well on my github branch. The basics are here I think, still this
portion really needs a careful review. I have done some basic tests
and things are basically working, but I have been able to break things
pretty easily when using some exotic characters. The conversion tables
look correct, I have tested it using my module which implements NFKC
(https://github.com/michaelpq/pg_plugins/tree/master/pg_sasl_prepare),
still much refinement needs to be done.
--
Michael
Attachments:
On Fri, Feb 17, 2017 at 7:29 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Wed, Feb 15, 2017 at 9:27 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Wed, Feb 15, 2017 at 7:58 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 02/09/2017 09:33 AM, Michael Paquier wrote:
Now regarding the shape of the implementation for SCRAM, we need one
thing: a set of routines in src/common/ to build decompositions for a
given UTF-8 string with conversion UTF8 string <=> pg_wchar array, the
decomposition and the reordering. The extension attached roughly
implements that. What we can actually do as well is have in contrib/ a
module that does NFK[C|D] using the base APIs in src/common/. Using
arrays of pg_wchar (integers) to manipulate the characters, we can
validate and have a set of regression tests that do *not* have to
print non-ASCII characters.A contrib module or built-in extra functions to deal with Unicode characters
might be handy for a lot of things. But I'd leave that out for now, to keep
this patch minimal.No problem from me. I'll get something for SASLprep in the shape of
something like the above. It should not take me long.OK, attached is a patch that implements SASLprep that needs to be
applied on top of the other ones. When working on the table reduction,
the worst size was at 2.4MB. After removing all the characters with a
class of 0 and no decomposition, I am able to get that down to 570kB.
After splitting the decompositions by size into their own tables, it
got down to 120kB, which is even nicer. One thing that I forgot
previously was the handling of the decomposition of Hangul characters
(Korean stuff) which is algorithmic, so you actually do not need a
table for them. The algorithm is here for the curious =>
http://unicode.org/reports/tr15/tr15-18.html#Hangul.The patch includes the conversion tables, which is why it is large,
and the perl script that I used to generate it. It has been pushed as
well on my github branch. The basics are here I think, still this
portion really needs a careful review. I have done some basic tests
and things are basically working, but I have been able to break things
pretty easily when using some exotic characters. The conversion tables
look correct, I have tested it using my module which implements NFKC
(https://github.com/michaelpq/pg_plugins/tree/master/pg_sasl_prepare),
still much refinement needs to be done.
Gosh, this SCRAM stuff seems to be taking us pretty deeply into
dealing with encoding details which apparently we haven't formerly
needed to worry about. That is a little surprising and maybe
something we should try to avoid?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Feb 19, 2017 at 6:55 PM, Robert Haas <robertmhaas@gmail.com> wrote:
Gosh, this SCRAM stuff seems to be taking us pretty deeply into
dealing with encoding details which apparently we haven't formerly
needed to worry about. That is a little surprising and maybe
something we should try to avoid?
The RFC of SCRAM, RFC5802 is clear on the matter
(https://tools.ietf.org/html/rfc5802), SASLprep needs NFKC (RFC4013
here, the worst in the set https://tools.ietf.org/html/rfc4013) if we
want our implementation to be compatible with any other Postgres
driver that implement things at protocol level without libpq. I think
that JDBC is one of those things. So I am afraid we cannot avoid it if
we want SCRAM.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Feb 15, 2017 at 8:28 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 02/07/2017 04:20 AM, Michael Paquier wrote:
--- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -247,6 +247,7 @@ Section: Class 28 - Invalid Authorization Specification28000 E ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION
invalid_authorization_specification
28P01 E ERRCODE_INVALID_PASSWORD
invalid_password
+28P01 E ERRCODE_INVALID_NONCE
invalid_nonceHaving two error codes with the same SQLSTATE is not cool, and tripped the
assertion in PL/python. I removed the new error code, it was only used in
one place, and ERRCODE_PROTOCOL_VIOLATIOn was more appropriate there anyway.Attached is a new set of patches, with that fixed. Thanks for the report
Aleksander!
There is something that I think is still unwelcome in this patch: the
interface in pg_hba.conf. I mentioned that in the previous thread but
now if you want to match a user and a database with a scram password
you need to do that with the current set of patches:
local $dbname $user scram
That's not really portable as SCRAM is one protocol in the SASL
family, and even worse in our case we use SCRAM-SHA-256. I'd like to
change pg_hhba.conf to be as follows:
local $dbname $user sasl protocol=scram_sha_256
This is extensible for the future, and protocol is a mandatory option
that would have now just a single value: scram_sha_256. Heikki,
others, are you fine with that?
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Feb 19, 2017 at 10:07 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
There is something that I think is still unwelcome in this patch: the
interface in pg_hba.conf. I mentioned that in the previous thread but
now if you want to match a user and a database with a scram password
you need to do that with the current set of patches:
local $dbname $user scram
That's not really portable as SCRAM is one protocol in the SASL
family, and even worse in our case we use SCRAM-SHA-256. I'd like to
change pg_hba.conf to be as follows:
local $dbname $user sasl protocol=scram_sha_256
This is extensible for the future, and protocol is a mandatory option
that would have now just a single value: scram_sha_256. Heikki,
others, are you fine with that?
I have implemented that as 0009 which is attached, and need to be
applied on the rest of upthread. I am not sure if we want to make the
case where no protocol is specified map to everything. This would be a
tricky support for users in the future if new authentication
mechanisms for SASL are added in the future.
Another issue that I have is: do we really want to have
password_encryption being set to "scram" for verifiers of
SCRAM-SHA-256? I would think that scram_sha_256 makes the most sense.
Who knows, perhaps there could be in a couple of years a SHA-SHA-512..
At the same time, attached is a new version of 0008 that implements
SASLprep, I have stabilized the beast after fixing some allocation
calculations when converting the decomposed pg_wchar array back to a
utf8 string.
--
Michael
Attachments:
0009-Make-hba-configuration-for-SASL-more-extensible.patchapplication/octet-stream; name=0009-Make-hba-configuration-for-SASL-more-extensible.patchDownload
From 84ea837dda62b29fcd1cb709802c754f517208ee Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 20 Feb 2017 14:15:18 +0900
Subject: [PATCH 9/9] Make hba configuration for SASL more extensible
The entries of pg_hba.conf are changed from "scram" to that:
"sasl protocol=scram_sha_256". SASL supporting many families of
authentication mechanisms, this likely makes the most sense. protocol
is as well a mandatory parameter. In the future if other mechanisms
are added this will prove to be very handy, by being able for example
to have a list of mechanisms defined.
Documentation and regression tests are updated according to that.
---
doc/src/sgml/client-auth.sgml | 46 +++++++++++++++++++++++--------
src/backend/libpq/auth.c | 10 +++++--
src/backend/libpq/hba.c | 31 +++++++++++++++++++--
src/backend/libpq/pg_hba.conf.sample | 4 +--
src/bin/initdb/initdb.c | 14 +++++-----
src/include/libpq/hba.h | 1 +
src/test/recovery/t/009_authentication.pl | 14 +++++++---
7 files changed, 91 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index f27d417f65..125a07325a 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -423,11 +423,12 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</varlistentry>
<varlistentry>
- <term><literal>scram</></term>
+ <term><literal>sasl</></term>
<listitem>
<para>
Require the client to supply a password encrypted with
- SCRAM-SHA-256 for authentication.
+ a protocol compatible with SASL exchange protocol, like
+ SCRAM-SHA-256, for authentication.
See <xref linkend="auth-password"> for details.
</para>
</listitem>
@@ -684,19 +685,19 @@ host postgres all 192.168.93.0/24 ident
# "postgres" if the user's password is correctly supplied.
#
# TYPE DATABASE USER ADDRESS METHOD
-host postgres all 192.168.12.10/32 scram
+host postgres all 192.168.12.10/32 sasl protocol=scram_sha_256
# Allow any user from hosts in the example.com domain to connect to
# any database if the user's password is correctly supplied.
#
-# Most users use SCRAM authentication, but some users use older clients
-# that don't support SCRAM authentication, and need to be able to log
-# in using MD5 authentication. Such users are put in the @md5users
-# group, everyone else must use SCRAM.
+# Most users use SCRAM-SHA-256 authentication, but some users use older
+# clients that don't support SCRAM-SHA-256 authentication, and need to be
+# able to log in using MD5 authentication. Such users are put in the @md5users
+# group, everyone else must use SCRAM-SHA-256.
#
# TYPE DATABASE USER ADDRESS METHOD
host all @md5users .example.com md5
-host all all .example.com scram
+host all all .example.com sasl protocol=scram_sha_256
# In the absence of preceding "host" lines, these two lines will
# reject all connections from 192.168.54.1 (since that entry will be
@@ -942,8 +943,8 @@ omicron bryanh guest1
</para>
<para>
- <literal>scram</>, as described in
- <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink> is
+ <literal>sasl</>, as described in
+ <ulink url="https://tools.ietf.org/html/rfc4422">RFC4422</ulink> is
defined to be more robust more than <literal>md5</> from a security
point of view as it protects from cases where the hashed password is
taken directly from <structname>pg_authid</structname> in which case
@@ -951,8 +952,29 @@ omicron bryanh guest1
the password behind it. It protects as well from password interception
and data sniffing where the password data could be directly obtained
from the network as well as man-in-the-middle (MITM) attacks. So it
- is strongly encouraged to use <literal>scram</> over <literal>md5</> for
- password-based deployments.
+ is strongly encouraged to use <literal>sasl</> over <literal>md5</> for
+ password-based deployments. <productname>SASL</> supports many families
+ of authentication mechanisms, <productname>PostgreSQL</> supporting only
+ <literal>SCRAM-SHA-256</literal> as described in
+ <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink>.
+ </para>
+
+ <para>
+ The following configuration options are supported for <productname>SASL</productname>:
+ <variablelist>
+ <varlistentry>
+ <term><literal>protocol</literal></term>
+ <listitem>
+ <para>
+ Sets the exchange protocol supported. This parameter is mandatory
+ and only the authentication mechanism listed are supported for the
+ user attempting a connection. It can be to <literal>scram_sha_256</>
+ to authorize users to connect using <literal>SCRAM-SHA-256</literal>
+ as authentication mechanism for the SASL exchange protocol.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</para>
<para>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index e475366ef3..2adfb8c4d4 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -818,8 +818,14 @@ CheckSASLAuth(Port *port, char **logdetail)
* guess that a server is expecting SASL or MD5 depending on the answer
* given by the backend without the user providing a password first.
*/
- sendAuthRequest(port, AUTH_REQ_SASL, SCRAM_SHA256_NAME,
- strlen(SCRAM_SHA256_NAME) + 1);
+ if (strcmp(port->hba->sasl_protocol, "scram_sha_256") == 0)
+ sendAuthRequest(port, AUTH_REQ_SASL, SCRAM_SHA256_NAME,
+ strlen(SCRAM_SHA256_NAME) + 1);
+ else
+ ereport(FATAL,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SASL protocol %s is not supported",
+ port->hba->sasl_protocol)));
/*
* If the user doesn't exist, or doesn't have a valid password, or
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 8c793e6389..e8e9a67b64 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -128,7 +128,7 @@ static const char *const UserAuthName[] =
"ident",
"password",
"md5",
- "scram",
+ "sasl",
"gss",
"sspi",
"pam",
@@ -1327,7 +1327,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
}
parsedline->auth_method = uaMD5;
}
- else if (strcmp(token->string, "scram") == 0)
+ else if (strcmp(token->string, "sasl") == 0)
parsedline->auth_method = uaSASL;
else if (strcmp(token->string, "pam") == 0)
#ifdef USE_PAM
@@ -1539,6 +1539,11 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
}
+ if (parsedline->auth_method == uaSASL)
+ {
+ MANDATORY_AUTH_ARG(parsedline->sasl_protocol, "protocol", "sasl");
+ }
+
/*
* Enforce any parameters implied by other settings.
*/
@@ -1824,6 +1829,21 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
hbaline->radiusidentifier = pstrdup(val);
}
+ else if (strcmp(name, "protocol") == 0)
+ {
+ if (hbaline->auth_method != uaSASL)
+ INVALID_AUTH_OPTION("protocol", gettext_noop("sasl"));
+ if (strcmp(val, "scram_sha_256") != 0)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("invalid protocol name for SASL: \"%s\"", val),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ *err_msg = psprintf("invalid protocl name for SASL: \"%s\"", val);
+ }
+ hbaline->sasl_protocol = pstrdup(val);
+ }
else
{
ereport(elevel,
@@ -2080,6 +2100,13 @@ gethba_options(HbaLine *hba)
options[noptions++] =
CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
+ if (hba->auth_method == uaSASL)
+ {
+ if (hba->sasl_protocol)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("protocol=%s", hba->sasl_protocol));
+ }
+
if (hba->auth_method == uaLDAP)
{
if (hba->ldapserver)
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 73f7973ea2..3b04d2367f 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -42,9 +42,9 @@
# or "samenet" to match any address in any subnet that the server is
# directly connected to.
#
-# METHOD can be "trust", "reject", "md5", "password", "scram", "gss",
+# METHOD can be "trust", "reject", "md5", "password", "sasl", "gss",
# "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
-# "password" sends passwords in clear text; "md5" or "scram" are preferred
+# "password" sends passwords in clear text; "md5" or "sasl" are preferred
# since they send encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 20ec2150bc..dfa95d05aa 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -76,7 +76,7 @@
extern const char *select_default_timezone(const char *share_path);
static const char *const auth_methods_host[] = {
- "trust", "reject", "md5", "password", "scram", "ident", "radius",
+ "trust", "reject", "md5", "password", "sasl", "ident", "radius",
#ifdef ENABLE_GSS
"gss",
#endif
@@ -98,7 +98,7 @@ static const char *const auth_methods_host[] = {
NULL
};
static const char *const auth_methods_local[] = {
- "trust", "reject", "md5", "scram", "password", "peer", "radius",
+ "trust", "reject", "md5", "sasl", "password", "peer", "radius",
#ifdef USE_PAM
"pam", "pam ",
#endif
@@ -1129,8 +1129,8 @@ setup_config(void)
"#update_process_title = off");
#endif
- if (strcmp(authmethodlocal, "scram") == 0 ||
- strcmp(authmethodhost, "scram") == 0)
+ if (strcmp(authmethodlocal, "sasl") == 0 ||
+ strcmp(authmethodhost, "sasl") == 0)
{
conflines = replace_token(conflines,
"#password_encryption = md5",
@@ -2317,16 +2317,16 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost)
{
if ((strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0) &&
+ strcmp(authmethodlocal, "sasl") == 0) &&
(strcmp(authmethodhost, "md5") == 0 ||
strcmp(authmethodhost, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0) &&
+ strcmp(authmethodlocal, "sasl") == 0) &&
!(pwprompt || pwfilename))
{
fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
(strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0)
+ strcmp(authmethodlocal, "sasl") == 0)
? authmethodlocal
: authmethodhost);
exit(1);
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 8f55edb16a..51968c98b8 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -93,6 +93,7 @@ typedef struct HbaLine
char *radiussecret;
char *radiusidentifier;
int radiusport;
+ char *sasl_protocol;
} HbaLine;
typedef struct IdentLine
diff --git a/src/test/recovery/t/009_authentication.pl b/src/test/recovery/t/009_authentication.pl
index 16be7f5cc8..c68a1093f6 100644
--- a/src/test/recovery/t/009_authentication.pl
+++ b/src/test/recovery/t/009_authentication.pl
@@ -16,11 +16,17 @@ use Test::More tests => 12;
# and then execute a reload to refresh it.
sub reset_pg_hba
{
- my $node = shift;
- my $hba_method = shift;
+ my ($node, $hba_method, $options) = @_;
unlink($node->data_dir . '/pg_hba.conf');
- $node->append_conf('pg_hba.conf', "local all all $hba_method");
+ if (defined($options))
+ {
+ $node->append_conf('pg_hba.conf', "local all all $hba_method $options");
+ }
+ else
+ {
+ $node->append_conf('pg_hba.conf', "local all all $hba_method");
+ }
$node->reload;
}
@@ -71,7 +77,7 @@ SKIP:
# For "scram" method, user "plain_role" and "scram_role" should be able to
# connect.
- reset_pg_hba($node, 'scram');
+ reset_pg_hba($node, 'sasl', 'protocol=scram_sha_256');
test_role($node, 'scram_role', 'scram', 0);
test_role($node, 'md5_role', 'scram', 2);
test_role($node, 'plain_role', 'scram', 0);
--
2.11.1
Hi!
Currently I don't see any significant flaws in these patches. However I
would like to verify that implemented algorithms are compatible with
algorithms implemented by third party.
For instance, for user 'eax' and password 'pass' I got the following
record in pg_authid:
```
scram-sha-256:
xtznkRN/nc/1DQ==:
4096:
2387c124a3139a276b848c910f43ece05dd670d0977ace4f20d724af522312e4:
5e3bdd6584880198b0375acabd8754c460af2389499f71a756660a10a8aaa843
```
Let's say I would like to implement SCRAM in pure Python, for instance
add it to pg8000 driver. Firstly I need to know how to generate server
key and client key having only user name and password. Somehow like
this:
```
import base64
import hashlib
base64.b16encode(hashlib.pbkdf2_hmac('sha256', b'pass',
... base64.b64decode(b'xtznkRN/nc/1DQ=='), 4096))
b'14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3'
```
Naturally it doesn't work because both SCRAM_SERVER_KEY_NAME and
SCRAM_CLIENT_KEY_NAME should also be involved. I see PostgreSQL
implementation just in front of me but unfortunately I'm still having
problems calculating exactly the same server key and client key. It makes
me worry whether PostgreSQL implementation is OK.
Could you please give an example of how to do it?
On Mon, Feb 20, 2017 at 03:29:19PM +0900, Michael Paquier wrote:
On Sun, Feb 19, 2017 at 10:07 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:There is something that I think is still unwelcome in this patch: the
interface in pg_hba.conf. I mentioned that in the previous thread but
now if you want to match a user and a database with a scram password
you need to do that with the current set of patches:
local $dbname $user scram
That's not really portable as SCRAM is one protocol in the SASL
family, and even worse in our case we use SCRAM-SHA-256. I'd like to
change pg_hba.conf to be as follows:
local $dbname $user sasl protocol=scram_sha_256
This is extensible for the future, and protocol is a mandatory option
that would have now just a single value: scram_sha_256. Heikki,
others, are you fine with that?I have implemented that as 0009 which is attached, and need to be
applied on the rest of upthread. I am not sure if we want to make the
case where no protocol is specified map to everything. This would be a
tricky support for users in the future if new authentication
mechanisms for SASL are added in the future.Another issue that I have is: do we really want to have
password_encryption being set to "scram" for verifiers of
SCRAM-SHA-256? I would think that scram_sha_256 makes the most sense.
Who knows, perhaps there could be in a couple of years a SHA-SHA-512..At the same time, attached is a new version of 0008 that implements
SASLprep, I have stabilized the beast after fixing some allocation
calculations when converting the decomposed pg_wchar array back to a
utf8 string.
--
Michael
--
Best regards,
Aleksander Alekseev
Speaking about flaws, it looks like there is a memory leak in
array_to_utf procedure - result is allocated twice.
On Mon, Feb 20, 2017 at 02:51:13PM +0300, Aleksander Alekseev wrote:
Hi!
Currently I don't see any significant flaws in these patches. However I
would like to verify that implemented algorithms are compatible with
algorithms implemented by third party.For instance, for user 'eax' and password 'pass' I got the following
record in pg_authid:```
scram-sha-256:
xtznkRN/nc/1DQ==:
4096:
2387c124a3139a276b848c910f43ece05dd670d0977ace4f20d724af522312e4:
5e3bdd6584880198b0375acabd8754c460af2389499f71a756660a10a8aaa843
```Let's say I would like to implement SCRAM in pure Python, for instance
add it to pg8000 driver. Firstly I need to know how to generate server
key and client key having only user name and password. Somehow like
this:```
import base64
import hashlib
base64.b16encode(hashlib.pbkdf2_hmac('sha256', b'pass',... base64.b64decode(b'xtznkRN/nc/1DQ=='), 4096))
b'14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3'
```Naturally it doesn't work because both SCRAM_SERVER_KEY_NAME and
SCRAM_CLIENT_KEY_NAME should also be involved. I see PostgreSQL
implementation just in front of me but unfortunately I'm still having
problems calculating exactly the same server key and client key. It makes
me worry whether PostgreSQL implementation is OK.Could you please give an example of how to do it?
On Mon, Feb 20, 2017 at 03:29:19PM +0900, Michael Paquier wrote:
On Sun, Feb 19, 2017 at 10:07 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:There is something that I think is still unwelcome in this patch: the
interface in pg_hba.conf. I mentioned that in the previous thread but
now if you want to match a user and a database with a scram password
you need to do that with the current set of patches:
local $dbname $user scram
That's not really portable as SCRAM is one protocol in the SASL
family, and even worse in our case we use SCRAM-SHA-256. I'd like to
change pg_hba.conf to be as follows:
local $dbname $user sasl protocol=scram_sha_256
This is extensible for the future, and protocol is a mandatory option
that would have now just a single value: scram_sha_256. Heikki,
others, are you fine with that?I have implemented that as 0009 which is attached, and need to be
applied on the rest of upthread. I am not sure if we want to make the
case where no protocol is specified map to everything. This would be a
tricky support for users in the future if new authentication
mechanisms for SASL are added in the future.Another issue that I have is: do we really want to have
password_encryption being set to "scram" for verifiers of
SCRAM-SHA-256? I would think that scram_sha_256 makes the most sense.
Who knows, perhaps there could be in a couple of years a SHA-SHA-512..At the same time, attached is a new version of 0008 that implements
SASLprep, I have stabilized the beast after fixing some allocation
calculations when converting the decomposed pg_wchar array back to a
utf8 string.
--
Michael--
Best regards,
Aleksander Alekseev
--
Best regards,
Aleksander Alekseev
And a few more things I've noticed after a closer look:
* build_client_first_message does not free `state->client_nonce` if
second malloc (for `buf`) fails
* same for `state->client_first_message_bare`
* ... and most other procedures declared in fe-auth-scram.c file
(see malloc and strdup calls)
* scram_Normalize doesn't check malloc return value
Sorry for lots of emails.
On Mon, Feb 20, 2017 at 03:15:14PM +0300, Aleksander Alekseev wrote:
Speaking about flaws, it looks like there is a memory leak in
array_to_utf procedure - result is allocated twice.On Mon, Feb 20, 2017 at 02:51:13PM +0300, Aleksander Alekseev wrote:
Hi!
Currently I don't see any significant flaws in these patches. However I
would like to verify that implemented algorithms are compatible with
algorithms implemented by third party.For instance, for user 'eax' and password 'pass' I got the following
record in pg_authid:```
scram-sha-256:
xtznkRN/nc/1DQ==:
4096:
2387c124a3139a276b848c910f43ece05dd670d0977ace4f20d724af522312e4:
5e3bdd6584880198b0375acabd8754c460af2389499f71a756660a10a8aaa843
```Let's say I would like to implement SCRAM in pure Python, for instance
add it to pg8000 driver. Firstly I need to know how to generate server
key and client key having only user name and password. Somehow like
this:```
import base64
import hashlib
base64.b16encode(hashlib.pbkdf2_hmac('sha256', b'pass',... base64.b64decode(b'xtznkRN/nc/1DQ=='), 4096))
b'14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3'
```Naturally it doesn't work because both SCRAM_SERVER_KEY_NAME and
SCRAM_CLIENT_KEY_NAME should also be involved. I see PostgreSQL
implementation just in front of me but unfortunately I'm still having
problems calculating exactly the same server key and client key. It makes
me worry whether PostgreSQL implementation is OK.Could you please give an example of how to do it?
On Mon, Feb 20, 2017 at 03:29:19PM +0900, Michael Paquier wrote:
On Sun, Feb 19, 2017 at 10:07 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:There is something that I think is still unwelcome in this patch: the
interface in pg_hba.conf. I mentioned that in the previous thread but
now if you want to match a user and a database with a scram password
you need to do that with the current set of patches:
local $dbname $user scram
That's not really portable as SCRAM is one protocol in the SASL
family, and even worse in our case we use SCRAM-SHA-256. I'd like to
change pg_hba.conf to be as follows:
local $dbname $user sasl protocol=scram_sha_256
This is extensible for the future, and protocol is a mandatory option
that would have now just a single value: scram_sha_256. Heikki,
others, are you fine with that?I have implemented that as 0009 which is attached, and need to be
applied on the rest of upthread. I am not sure if we want to make the
case where no protocol is specified map to everything. This would be a
tricky support for users in the future if new authentication
mechanisms for SASL are added in the future.Another issue that I have is: do we really want to have
password_encryption being set to "scram" for verifiers of
SCRAM-SHA-256? I would think that scram_sha_256 makes the most sense.
Who knows, perhaps there could be in a couple of years a SHA-SHA-512..At the same time, attached is a new version of 0008 that implements
SASLprep, I have stabilized the beast after fixing some allocation
calculations when converting the decomposed pg_wchar array back to a
utf8 string.
--
Michael--
Best regards,
Aleksander Alekseev--
Best regards,
Aleksander Alekseev
--
Best regards,
Aleksander Alekseev
On Mon, Feb 20, 2017 at 9:41 PM, Aleksander Alekseev
<a.alekseev@postgrespro.ru> wrote:
Speaking about flaws, it looks like there is a memory leak in
array_to_utf procedure - result is allocated twice.
Pushed a fix for this one on my branch.
And a few more things I've noticed after a closer look:
* build_client_first_message does not free `state->client_nonce` if
second malloc (for `buf`) fails
* same for `state->client_first_message_bare`
* ... and most other procedures declared in fe-auth-scram.c file
(see malloc and strdup calls)
You are visibly missing pg_fe_scram_free().
* scram_Normalize doesn't check malloc return value
Yes, I am aware of this one. This makes the interface utterly ugly
though because an error log message needs to be handled across many
API layers. We could just assume anything returning NULL is equivalent
to an OOM and nothing else though.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Feb 21, 2017 at 9:53 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Mon, Feb 20, 2017 at 9:41 PM, Aleksander Alekseev
<a.alekseev@postgrespro.ru> wrote:Speaking about flaws, it looks like there is a memory leak in
array_to_utf procedure - result is allocated twice.Pushed a fix for this one on my branch.
And a few more things I've noticed after a closer look:
* build_client_first_message does not free `state->client_nonce` if
second malloc (for `buf`) fails
* same for `state->client_first_message_bare`
* ... and most other procedures declared in fe-auth-scram.c file
(see malloc and strdup calls)You are visibly missing pg_fe_scram_free().
* scram_Normalize doesn't check malloc return value
Yes, I am aware of this one. This makes the interface utterly ugly
though because an error log message needs to be handled across many
API layers. We could just assume anything returning NULL is equivalent
to an OOM and nothing else though.
Attached is a new patch set. I have combined SASLprep with the rest
and fixed some conflicts. At the same time when going through NFKC
this morning I have noticed that the implementation was doing the
canonical decomposition and reordered the characters using the
combining classes, but the string recomposition was still missing.
This is addressed in this patch set, and well as on my dev tree:
https://github.com/michaelpq/postgres/tree/scram
--
Michael
Attachments:
0001-Refactor-SHA2-functions-and-move-them-to-src-common.patchapplication/octet-stream; name=0001-Refactor-SHA2-functions-and-move-them-to-src-common.patchDownload
From 70807133374c749135a8a38c7b83a883dae16995 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 7 Dec 2016 14:11:10 +0900
Subject: [PATCH 1/8] Refactor SHA2 functions and move them to src/common/
This way both frontend and backends can refer to them if needed. Those
functions are taken from pgcrypto, which now fetches directly the source
files it needs from src/common/ when compiling its library.
A new interface, which is more PG-like is designed for those SHA2 functions,
allowing to link to either OpenSSL or the in-core stuff taken from KAME
as need be, which is the most flexible solution.
---
contrib/pgcrypto/.gitignore | 4 +
contrib/pgcrypto/Makefile | 9 +-
contrib/pgcrypto/internal-sha2.c | 82 +++++++--------
contrib/pgcrypto/sha2.h | 100 ------------------
src/common/Makefile | 6 ++
{contrib/pgcrypto => src/common}/sha2.c | 174 +++++++++++++++++---------------
src/common/sha2_openssl.c | 102 +++++++++++++++++++
src/include/common/sha2.h | 115 +++++++++++++++++++++
src/tools/msvc/Mkvcbuild.pm | 20 +++-
9 files changed, 385 insertions(+), 227 deletions(-)
delete mode 100644 contrib/pgcrypto/sha2.h
rename {contrib/pgcrypto => src/common}/sha2.c (82%)
create mode 100644 src/common/sha2_openssl.c
create mode 100644 src/include/common/sha2.h
diff --git a/contrib/pgcrypto/.gitignore b/contrib/pgcrypto/.gitignore
index 5dcb3ff972..30619bfbbf 100644
--- a/contrib/pgcrypto/.gitignore
+++ b/contrib/pgcrypto/.gitignore
@@ -1,3 +1,7 @@
+# Source file copied from src/common
+/sha2.c
+/sha2_openssl.c
+
# Generated subdirectories
/log/
/results/
diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index f65d84d1f3..14e74f899c 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -4,7 +4,7 @@ INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
pgp-mpi-internal.c imath.c
INT_TESTS = sha2
-OSSL_SRCS = openssl.c pgp-mpi-openssl.c
+OSSL_SRCS = openssl.c pgp-mpi-openssl.c sha2_openssl.c
OSSL_TESTS = sha2 des 3des cast5
ZLIB_TST = pgp-compression
@@ -59,6 +59,13 @@ SHLIB_LINK += $(filter -leay32, $(LIBS))
SHLIB_LINK += -lws2_32
endif
+# Compiling pgcrypto with those two raw files is necessary as long
+# as none of their routines are used by the backend code. Note doing
+# so can either result in library loading failures or linking resolution
+# failures at compilation depending on the environment used.
+sha2.c sha2_openssl.c: % : $(top_srcdir)/src/common/%
+ rm -f $@ && $(LN_S) $< .
+
rijndael.o: rijndael.tbl
rijndael.tbl:
diff --git a/contrib/pgcrypto/internal-sha2.c b/contrib/pgcrypto/internal-sha2.c
index 55ec7e16bd..e06f55445e 100644
--- a/contrib/pgcrypto/internal-sha2.c
+++ b/contrib/pgcrypto/internal-sha2.c
@@ -33,8 +33,8 @@
#include <time.h>
+#include "common/sha2.h"
#include "px.h"
-#include "sha2.h"
void init_sha224(PX_MD *h);
void init_sha256(PX_MD *h);
@@ -46,43 +46,43 @@ void init_sha512(PX_MD *h);
static unsigned
int_sha224_len(PX_MD *h)
{
- return SHA224_DIGEST_LENGTH;
+ return PG_SHA224_DIGEST_LENGTH;
}
static unsigned
int_sha224_block_len(PX_MD *h)
{
- return SHA224_BLOCK_LENGTH;
+ return PG_SHA224_BLOCK_LENGTH;
}
static void
int_sha224_update(PX_MD *h, const uint8 *data, unsigned dlen)
{
- SHA224_CTX *ctx = (SHA224_CTX *) h->p.ptr;
+ pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr;
- SHA224_Update(ctx, data, dlen);
+ pg_sha224_update(ctx, data, dlen);
}
static void
int_sha224_reset(PX_MD *h)
{
- SHA224_CTX *ctx = (SHA224_CTX *) h->p.ptr;
+ pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr;
- SHA224_Init(ctx);
+ pg_sha224_init(ctx);
}
static void
int_sha224_finish(PX_MD *h, uint8 *dst)
{
- SHA224_CTX *ctx = (SHA224_CTX *) h->p.ptr;
+ pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr;
- SHA224_Final(dst, ctx);
+ pg_sha224_final(ctx, dst);
}
static void
int_sha224_free(PX_MD *h)
{
- SHA224_CTX *ctx = (SHA224_CTX *) h->p.ptr;
+ pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr;
px_memset(ctx, 0, sizeof(*ctx));
px_free(ctx);
@@ -94,43 +94,43 @@ int_sha224_free(PX_MD *h)
static unsigned
int_sha256_len(PX_MD *h)
{
- return SHA256_DIGEST_LENGTH;
+ return PG_SHA256_DIGEST_LENGTH;
}
static unsigned
int_sha256_block_len(PX_MD *h)
{
- return SHA256_BLOCK_LENGTH;
+ return PG_SHA256_BLOCK_LENGTH;
}
static void
int_sha256_update(PX_MD *h, const uint8 *data, unsigned dlen)
{
- SHA256_CTX *ctx = (SHA256_CTX *) h->p.ptr;
+ pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr;
- SHA256_Update(ctx, data, dlen);
+ pg_sha256_update(ctx, data, dlen);
}
static void
int_sha256_reset(PX_MD *h)
{
- SHA256_CTX *ctx = (SHA256_CTX *) h->p.ptr;
+ pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr;
- SHA256_Init(ctx);
+ pg_sha256_init(ctx);
}
static void
int_sha256_finish(PX_MD *h, uint8 *dst)
{
- SHA256_CTX *ctx = (SHA256_CTX *) h->p.ptr;
+ pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr;
- SHA256_Final(dst, ctx);
+ pg_sha256_final(ctx, dst);
}
static void
int_sha256_free(PX_MD *h)
{
- SHA256_CTX *ctx = (SHA256_CTX *) h->p.ptr;
+ pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr;
px_memset(ctx, 0, sizeof(*ctx));
px_free(ctx);
@@ -142,43 +142,43 @@ int_sha256_free(PX_MD *h)
static unsigned
int_sha384_len(PX_MD *h)
{
- return SHA384_DIGEST_LENGTH;
+ return PG_SHA384_DIGEST_LENGTH;
}
static unsigned
int_sha384_block_len(PX_MD *h)
{
- return SHA384_BLOCK_LENGTH;
+ return PG_SHA384_BLOCK_LENGTH;
}
static void
int_sha384_update(PX_MD *h, const uint8 *data, unsigned dlen)
{
- SHA384_CTX *ctx = (SHA384_CTX *) h->p.ptr;
+ pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr;
- SHA384_Update(ctx, data, dlen);
+ pg_sha384_update(ctx, data, dlen);
}
static void
int_sha384_reset(PX_MD *h)
{
- SHA384_CTX *ctx = (SHA384_CTX *) h->p.ptr;
+ pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr;
- SHA384_Init(ctx);
+ pg_sha384_init(ctx);
}
static void
int_sha384_finish(PX_MD *h, uint8 *dst)
{
- SHA384_CTX *ctx = (SHA384_CTX *) h->p.ptr;
+ pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr;
- SHA384_Final(dst, ctx);
+ pg_sha384_final(ctx, dst);
}
static void
int_sha384_free(PX_MD *h)
{
- SHA384_CTX *ctx = (SHA384_CTX *) h->p.ptr;
+ pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr;
px_memset(ctx, 0, sizeof(*ctx));
px_free(ctx);
@@ -190,43 +190,43 @@ int_sha384_free(PX_MD *h)
static unsigned
int_sha512_len(PX_MD *h)
{
- return SHA512_DIGEST_LENGTH;
+ return PG_SHA512_DIGEST_LENGTH;
}
static unsigned
int_sha512_block_len(PX_MD *h)
{
- return SHA512_BLOCK_LENGTH;
+ return PG_SHA512_BLOCK_LENGTH;
}
static void
int_sha512_update(PX_MD *h, const uint8 *data, unsigned dlen)
{
- SHA512_CTX *ctx = (SHA512_CTX *) h->p.ptr;
+ pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr;
- SHA512_Update(ctx, data, dlen);
+ pg_sha512_update(ctx, data, dlen);
}
static void
int_sha512_reset(PX_MD *h)
{
- SHA512_CTX *ctx = (SHA512_CTX *) h->p.ptr;
+ pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr;
- SHA512_Init(ctx);
+ pg_sha512_init(ctx);
}
static void
int_sha512_finish(PX_MD *h, uint8 *dst)
{
- SHA512_CTX *ctx = (SHA512_CTX *) h->p.ptr;
+ pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr;
- SHA512_Final(dst, ctx);
+ pg_sha512_final(ctx, dst);
}
static void
int_sha512_free(PX_MD *h)
{
- SHA512_CTX *ctx = (SHA512_CTX *) h->p.ptr;
+ pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr;
px_memset(ctx, 0, sizeof(*ctx));
px_free(ctx);
@@ -238,7 +238,7 @@ int_sha512_free(PX_MD *h)
void
init_sha224(PX_MD *md)
{
- SHA224_CTX *ctx;
+ pg_sha224_ctx *ctx;
ctx = px_alloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
@@ -258,7 +258,7 @@ init_sha224(PX_MD *md)
void
init_sha256(PX_MD *md)
{
- SHA256_CTX *ctx;
+ pg_sha256_ctx *ctx;
ctx = px_alloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
@@ -278,7 +278,7 @@ init_sha256(PX_MD *md)
void
init_sha384(PX_MD *md)
{
- SHA384_CTX *ctx;
+ pg_sha384_ctx *ctx;
ctx = px_alloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
@@ -298,7 +298,7 @@ init_sha384(PX_MD *md)
void
init_sha512(PX_MD *md)
{
- SHA512_CTX *ctx;
+ pg_sha512_ctx *ctx;
ctx = px_alloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
diff --git a/contrib/pgcrypto/sha2.h b/contrib/pgcrypto/sha2.h
deleted file mode 100644
index 501f0e0446..0000000000
--- a/contrib/pgcrypto/sha2.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* contrib/pgcrypto/sha2.h */
-/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */
-
-/*
- * FILE: sha2.h
- * AUTHOR: Aaron D. Gifford <me@aarongifford.com>
- *
- * Copyright (c) 2000-2001, Aaron D. Gifford
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
- */
-
-#ifndef _SHA2_H
-#define _SHA2_H
-
-/* avoid conflict with OpenSSL */
-#define SHA256_Init pg_SHA256_Init
-#define SHA256_Update pg_SHA256_Update
-#define SHA256_Final pg_SHA256_Final
-#define SHA384_Init pg_SHA384_Init
-#define SHA384_Update pg_SHA384_Update
-#define SHA384_Final pg_SHA384_Final
-#define SHA512_Init pg_SHA512_Init
-#define SHA512_Update pg_SHA512_Update
-#define SHA512_Final pg_SHA512_Final
-
-/*** SHA-224/256/384/512 Various Length Definitions ***********************/
-#define SHA224_BLOCK_LENGTH 64
-#define SHA224_DIGEST_LENGTH 28
-#define SHA224_DIGEST_STRING_LENGTH (SHA224_DIGEST_LENGTH * 2 + 1)
-#define SHA256_BLOCK_LENGTH 64
-#define SHA256_DIGEST_LENGTH 32
-#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
-#define SHA384_BLOCK_LENGTH 128
-#define SHA384_DIGEST_LENGTH 48
-#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1)
-#define SHA512_BLOCK_LENGTH 128
-#define SHA512_DIGEST_LENGTH 64
-#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1)
-
-
-/*** SHA-256/384/512 Context Structures *******************************/
-typedef struct _SHA256_CTX
-{
- uint32 state[8];
- uint64 bitcount;
- uint8 buffer[SHA256_BLOCK_LENGTH];
-} SHA256_CTX;
-typedef struct _SHA512_CTX
-{
- uint64 state[8];
- uint64 bitcount[2];
- uint8 buffer[SHA512_BLOCK_LENGTH];
-} SHA512_CTX;
-
-typedef SHA256_CTX SHA224_CTX;
-typedef SHA512_CTX SHA384_CTX;
-
-void SHA224_Init(SHA224_CTX *);
-void SHA224_Update(SHA224_CTX *, const uint8 *, size_t);
-void SHA224_Final(uint8[SHA224_DIGEST_LENGTH], SHA224_CTX *);
-
-void SHA256_Init(SHA256_CTX *);
-void SHA256_Update(SHA256_CTX *, const uint8 *, size_t);
-void SHA256_Final(uint8[SHA256_DIGEST_LENGTH], SHA256_CTX *);
-
-void SHA384_Init(SHA384_CTX *);
-void SHA384_Update(SHA384_CTX *, const uint8 *, size_t);
-void SHA384_Final(uint8[SHA384_DIGEST_LENGTH], SHA384_CTX *);
-
-void SHA512_Init(SHA512_CTX *);
-void SHA512_Update(SHA512_CTX *, const uint8 *, size_t);
-void SHA512_Final(uint8[SHA512_DIGEST_LENGTH], SHA512_CTX *);
-
-#endif /* _SHA2_H */
diff --git a/src/common/Makefile b/src/common/Makefile
index 03dfaa19c4..5ddfff8b44 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -44,6 +44,12 @@ OBJS_COMMON = config_info.o controldata_utils.o exec.o ip.o keywords.o \
md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \
string.o username.o wait_error.o
+ifeq ($(with_openssl),yes)
+OBJS_COMMON += sha2_openssl.o
+else
+OBJS_COMMON += sha2.o
+endif
+
OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_utils.o restricted_token.o
OBJS_SRV = $(OBJS_COMMON:%.o=%_srv.o)
diff --git a/contrib/pgcrypto/sha2.c b/src/common/sha2.c
similarity index 82%
rename from contrib/pgcrypto/sha2.c
rename to src/common/sha2.c
index 231f9dfbb0..496467507d 100644
--- a/contrib/pgcrypto/sha2.c
+++ b/src/common/sha2.c
@@ -1,5 +1,20 @@
-/* $OpenBSD: sha2.c,v 1.6 2004/05/03 02:57:36 millert Exp $ */
+/*-------------------------------------------------------------------------
+ *
+ * sha2.c
+ * Set of SHA functions for SHA-224, SHA-256, SHA-384 and SHA-512.
+ *
+ * This is the set of in-core functions used when there are no other
+ * alternative options like OpenSSL.
+ *
+ * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/common/sha2.c
+ *
+ *-------------------------------------------------------------------------
+ */
+/* $OpenBSD: sha2.c,v 1.6 2004/05/03 02:57:36 millert Exp $ */
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford <me@aarongifford.com>
@@ -32,16 +47,18 @@
* SUCH DAMAGE.
*
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
- *
- * contrib/pgcrypto/sha2.c
*/
+
+#ifndef FRONTEND
#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
#include <sys/param.h>
-#include "px.h"
-#include "sha2.h"
+#include "common/sha2.h"
/*
* UNROLLED TRANSFORM LOOP NOTE:
@@ -58,11 +75,9 @@
*/
/*** SHA-256/384/512 Various Length Definitions ***********************/
-/* NOTE: Most of these are in sha2.h */
-#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
-#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
-#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
-
+#define PG_SHA256_SHORT_BLOCK_LENGTH (PG_SHA256_BLOCK_LENGTH - 8)
+#define PG_SHA384_SHORT_BLOCK_LENGTH (PG_SHA384_BLOCK_LENGTH - 16)
+#define PG_SHA512_SHORT_BLOCK_LENGTH (PG_SHA512_BLOCK_LENGTH - 16)
/*** ENDIAN REVERSAL MACROS *******************************************/
#ifndef WORDS_BIGENDIAN
@@ -130,10 +145,9 @@
* library -- they are intended for private internal visibility/use
* only.
*/
-static void SHA512_Last(SHA512_CTX *);
-static void SHA256_Transform(SHA256_CTX *, const uint8 *);
-static void SHA512_Transform(SHA512_CTX *, const uint8 *);
-
+static void SHA512_Last(pg_sha512_ctx *context);
+static void SHA256_Transform(pg_sha256_ctx *context, const uint8 *data);
+static void SHA512_Transform(pg_sha512_ctx *context, const uint8 *data);
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
/* Hash constant words K for SHA-256: */
@@ -251,12 +265,12 @@ static const uint64 sha512_initial_hash_value[8] = {
/*** SHA-256: *********************************************************/
void
-SHA256_Init(SHA256_CTX *context)
+pg_sha256_init(pg_sha256_ctx *context)
{
if (context == NULL)
return;
- memcpy(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
- memset(context->buffer, 0, SHA256_BLOCK_LENGTH);
+ memcpy(context->state, sha256_initial_hash_value, PG_SHA256_DIGEST_LENGTH);
+ memset(context->buffer, 0, PG_SHA256_BLOCK_LENGTH);
context->bitcount = 0;
}
@@ -287,7 +301,7 @@ SHA256_Init(SHA256_CTX *context)
} while(0)
static void
-SHA256_Transform(SHA256_CTX *context, const uint8 *data)
+SHA256_Transform(pg_sha256_ctx *context, const uint8 *data)
{
uint32 a,
b,
@@ -358,7 +372,7 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
#else /* SHA2_UNROLL_TRANSFORM */
static void
-SHA256_Transform(SHA256_CTX *context, const uint8 *data)
+SHA256_Transform(pg_sha256_ctx *context, const uint8 *data)
{
uint32 a,
b,
@@ -448,7 +462,7 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
#endif /* SHA2_UNROLL_TRANSFORM */
void
-SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len)
+pg_sha256_update(pg_sha256_ctx *context, const uint8 *data, size_t len)
{
size_t freespace,
usedspace;
@@ -457,11 +471,11 @@ SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len)
if (len == 0)
return;
- usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+ usedspace = (context->bitcount >> 3) % PG_SHA256_BLOCK_LENGTH;
if (usedspace > 0)
{
/* Calculate how much free space is available in the buffer */
- freespace = SHA256_BLOCK_LENGTH - usedspace;
+ freespace = PG_SHA256_BLOCK_LENGTH - usedspace;
if (len >= freespace)
{
@@ -482,13 +496,13 @@ SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len)
return;
}
}
- while (len >= SHA256_BLOCK_LENGTH)
+ while (len >= PG_SHA256_BLOCK_LENGTH)
{
/* Process as many complete blocks as we can */
SHA256_Transform(context, data);
- context->bitcount += SHA256_BLOCK_LENGTH << 3;
- len -= SHA256_BLOCK_LENGTH;
- data += SHA256_BLOCK_LENGTH;
+ context->bitcount += PG_SHA256_BLOCK_LENGTH << 3;
+ len -= PG_SHA256_BLOCK_LENGTH;
+ data += PG_SHA256_BLOCK_LENGTH;
}
if (len > 0)
{
@@ -501,11 +515,11 @@ SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len)
}
static void
-SHA256_Last(SHA256_CTX *context)
+SHA256_Last(pg_sha256_ctx *context)
{
unsigned int usedspace;
- usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+ usedspace = (context->bitcount >> 3) % PG_SHA256_BLOCK_LENGTH;
#ifndef WORDS_BIGENDIAN
/* Convert FROM host byte order */
REVERSE64(context->bitcount, context->bitcount);
@@ -515,41 +529,41 @@ SHA256_Last(SHA256_CTX *context)
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
- if (usedspace <= SHA256_SHORT_BLOCK_LENGTH)
+ if (usedspace <= PG_SHA256_SHORT_BLOCK_LENGTH)
{
/* Set-up for the last transform: */
- memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace);
+ memset(&context->buffer[usedspace], 0, PG_SHA256_SHORT_BLOCK_LENGTH - usedspace);
}
else
{
- if (usedspace < SHA256_BLOCK_LENGTH)
+ if (usedspace < PG_SHA256_BLOCK_LENGTH)
{
- memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace);
+ memset(&context->buffer[usedspace], 0, PG_SHA256_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA256_Transform(context, context->buffer);
/* And set-up for the last transform: */
- memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+ memset(context->buffer, 0, PG_SHA256_SHORT_BLOCK_LENGTH);
}
}
else
{
/* Set-up for the last transform: */
- memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+ memset(context->buffer, 0, PG_SHA256_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Set the bit count: */
- *(uint64 *) &context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+ *(uint64 *) &context->buffer[PG_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
/* Final transform: */
SHA256_Transform(context, context->buffer);
}
void
-SHA256_Final(uint8 digest[], SHA256_CTX *context)
+pg_sha256_final(pg_sha256_ctx *context, uint8 *digest)
{
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != NULL)
@@ -567,22 +581,22 @@ SHA256_Final(uint8 digest[], SHA256_CTX *context)
}
}
#endif
- memcpy(digest, context->state, SHA256_DIGEST_LENGTH);
+ memcpy(digest, context->state, PG_SHA256_DIGEST_LENGTH);
}
/* Clean up state data: */
- px_memset(context, 0, sizeof(*context));
+ memset(context, 0, sizeof(pg_sha256_ctx));
}
/*** SHA-512: *********************************************************/
void
-SHA512_Init(SHA512_CTX *context)
+pg_sha512_init(pg_sha512_ctx *context)
{
if (context == NULL)
return;
- memcpy(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
- memset(context->buffer, 0, SHA512_BLOCK_LENGTH);
+ memcpy(context->state, sha512_initial_hash_value, PG_SHA512_DIGEST_LENGTH);
+ memset(context->buffer, 0, PG_SHA512_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
@@ -616,7 +630,7 @@ SHA512_Init(SHA512_CTX *context)
} while(0)
static void
-SHA512_Transform(SHA512_CTX *context, const uint8 *data)
+SHA512_Transform(pg_sha512_ctx *context, const uint8 *data)
{
uint64 a,
b,
@@ -684,7 +698,7 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
#else /* SHA2_UNROLL_TRANSFORM */
static void
-SHA512_Transform(SHA512_CTX *context, const uint8 *data)
+SHA512_Transform(pg_sha512_ctx *context, const uint8 *data)
{
uint64 a,
b,
@@ -774,7 +788,7 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
#endif /* SHA2_UNROLL_TRANSFORM */
void
-SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len)
+pg_sha512_update(pg_sha512_ctx *context, const uint8 *data, size_t len)
{
size_t freespace,
usedspace;
@@ -783,11 +797,11 @@ SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len)
if (len == 0)
return;
- usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+ usedspace = (context->bitcount[0] >> 3) % PG_SHA512_BLOCK_LENGTH;
if (usedspace > 0)
{
/* Calculate how much free space is available in the buffer */
- freespace = SHA512_BLOCK_LENGTH - usedspace;
+ freespace = PG_SHA512_BLOCK_LENGTH - usedspace;
if (len >= freespace)
{
@@ -808,13 +822,13 @@ SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len)
return;
}
}
- while (len >= SHA512_BLOCK_LENGTH)
+ while (len >= PG_SHA512_BLOCK_LENGTH)
{
/* Process as many complete blocks as we can */
SHA512_Transform(context, data);
- ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
- len -= SHA512_BLOCK_LENGTH;
- data += SHA512_BLOCK_LENGTH;
+ ADDINC128(context->bitcount, PG_SHA512_BLOCK_LENGTH << 3);
+ len -= PG_SHA512_BLOCK_LENGTH;
+ data += PG_SHA512_BLOCK_LENGTH;
}
if (len > 0)
{
@@ -827,11 +841,11 @@ SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len)
}
static void
-SHA512_Last(SHA512_CTX *context)
+SHA512_Last(pg_sha512_ctx *context)
{
unsigned int usedspace;
- usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+ usedspace = (context->bitcount[0] >> 3) % PG_SHA512_BLOCK_LENGTH;
#ifndef WORDS_BIGENDIAN
/* Convert FROM host byte order */
REVERSE64(context->bitcount[0], context->bitcount[0]);
@@ -842,42 +856,42 @@ SHA512_Last(SHA512_CTX *context)
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
- if (usedspace <= SHA512_SHORT_BLOCK_LENGTH)
+ if (usedspace <= PG_SHA512_SHORT_BLOCK_LENGTH)
{
/* Set-up for the last transform: */
- memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ memset(&context->buffer[usedspace], 0, PG_SHA512_SHORT_BLOCK_LENGTH - usedspace);
}
else
{
- if (usedspace < SHA512_BLOCK_LENGTH)
+ if (usedspace < PG_SHA512_BLOCK_LENGTH)
{
- memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
+ memset(&context->buffer[usedspace], 0, PG_SHA512_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA512_Transform(context, context->buffer);
/* And set-up for the last transform: */
- memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2);
+ memset(context->buffer, 0, PG_SHA512_BLOCK_LENGTH - 2);
}
}
else
{
/* Prepare for final transform: */
- memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH);
+ memset(context->buffer, 0, PG_SHA512_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits): */
- *(uint64 *) &context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
- *(uint64 *) &context->buffer[SHA512_SHORT_BLOCK_LENGTH + 8] = context->bitcount[0];
+ *(uint64 *) &context->buffer[PG_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(uint64 *) &context->buffer[PG_SHA512_SHORT_BLOCK_LENGTH + 8] = context->bitcount[0];
/* Final transform: */
SHA512_Transform(context, context->buffer);
}
void
-SHA512_Final(uint8 digest[], SHA512_CTX *context)
+pg_sha512_final(pg_sha512_ctx *context, uint8 *digest)
{
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != NULL)
@@ -896,38 +910,38 @@ SHA512_Final(uint8 digest[], SHA512_CTX *context)
}
}
#endif
- memcpy(digest, context->state, SHA512_DIGEST_LENGTH);
+ memcpy(digest, context->state, PG_SHA512_DIGEST_LENGTH);
}
/* Zero out state data */
- px_memset(context, 0, sizeof(*context));
+ memset(context, 0, sizeof(pg_sha512_ctx));
}
/*** SHA-384: *********************************************************/
void
-SHA384_Init(SHA384_CTX *context)
+pg_sha384_init(pg_sha384_ctx *context)
{
if (context == NULL)
return;
- memcpy(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
- memset(context->buffer, 0, SHA384_BLOCK_LENGTH);
+ memcpy(context->state, sha384_initial_hash_value, PG_SHA512_DIGEST_LENGTH);
+ memset(context->buffer, 0, PG_SHA384_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
void
-SHA384_Update(SHA384_CTX *context, const uint8 *data, size_t len)
+pg_sha384_update(pg_sha384_ctx *context, const uint8 *data, size_t len)
{
- SHA512_Update((SHA512_CTX *) context, data, len);
+ pg_sha512_update((pg_sha512_ctx *) context, data, len);
}
void
-SHA384_Final(uint8 digest[], SHA384_CTX *context)
+pg_sha384_final(pg_sha384_ctx *context, uint8 *digest)
{
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != NULL)
{
- SHA512_Last((SHA512_CTX *) context);
+ SHA512_Last((pg_sha512_ctx *) context);
/* Save the hash data for output: */
#ifndef WORDS_BIGENDIAN
@@ -941,32 +955,32 @@ SHA384_Final(uint8 digest[], SHA384_CTX *context)
}
}
#endif
- memcpy(digest, context->state, SHA384_DIGEST_LENGTH);
+ memcpy(digest, context->state, PG_SHA384_DIGEST_LENGTH);
}
/* Zero out state data */
- px_memset(context, 0, sizeof(*context));
+ memset(context, 0, sizeof(pg_sha384_ctx));
}
/*** SHA-224: *********************************************************/
void
-SHA224_Init(SHA224_CTX *context)
+pg_sha224_init(pg_sha224_ctx *context)
{
if (context == NULL)
return;
- memcpy(context->state, sha224_initial_hash_value, SHA256_DIGEST_LENGTH);
- memset(context->buffer, 0, SHA256_BLOCK_LENGTH);
+ memcpy(context->state, sha224_initial_hash_value, PG_SHA256_DIGEST_LENGTH);
+ memset(context->buffer, 0, PG_SHA256_BLOCK_LENGTH);
context->bitcount = 0;
}
void
-SHA224_Update(SHA224_CTX *context, const uint8 *data, size_t len)
+pg_sha224_update(pg_sha224_ctx *context, const uint8 *data, size_t len)
{
- SHA256_Update((SHA256_CTX *) context, data, len);
+ pg_sha256_update((pg_sha256_ctx *) context, data, len);
}
void
-SHA224_Final(uint8 digest[], SHA224_CTX *context)
+pg_sha224_final(pg_sha224_ctx *context, uint8 *digest)
{
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != NULL)
@@ -984,9 +998,9 @@ SHA224_Final(uint8 digest[], SHA224_CTX *context)
}
}
#endif
- memcpy(digest, context->state, SHA224_DIGEST_LENGTH);
+ memcpy(digest, context->state, PG_SHA224_DIGEST_LENGTH);
}
/* Clean up state data: */
- px_memset(context, 0, sizeof(*context));
+ memset(context, 0, sizeof(pg_sha224_ctx));
}
diff --git a/src/common/sha2_openssl.c b/src/common/sha2_openssl.c
new file mode 100644
index 0000000000..91d0c3924b
--- /dev/null
+++ b/src/common/sha2_openssl.c
@@ -0,0 +1,102 @@
+/*-------------------------------------------------------------------------
+ *
+ * sha2_openssl.c
+ * Set of wrapper routines on top of OpenSSL to support SHA-224
+ * SHA-256, SHA-384 and SHA-512 functions.
+ *
+ * This should only be used if code is compiled with OpenSSL support.
+ *
+ * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/common/sha2_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <openssl/sha.h>
+
+#include "common/sha2.h"
+
+
+/* Interface routines for SHA-256 */
+void
+pg_sha256_init(pg_sha256_ctx *ctx)
+{
+ SHA256_Init((SHA256_CTX *) ctx);
+}
+
+void
+pg_sha256_update(pg_sha256_ctx *ctx, const uint8 *data, size_t len)
+{
+ SHA256_Update((SHA256_CTX *) ctx, data, len);
+}
+
+void
+pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest)
+{
+ SHA256_Final(dest, (SHA256_CTX *) ctx);
+}
+
+/* Interface routines for SHA-512 */
+void
+pg_sha512_init(pg_sha512_ctx *ctx)
+{
+ SHA512_Init((SHA512_CTX *) ctx);
+}
+
+void
+pg_sha512_update(pg_sha512_ctx *ctx, const uint8 *data, size_t len)
+{
+ SHA512_Update((SHA512_CTX *) ctx, data, len);
+}
+
+void
+pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest)
+{
+ SHA512_Final(dest, (SHA512_CTX *) ctx);
+}
+
+/* Interface routines for SHA-384 */
+void
+pg_sha384_init(pg_sha384_ctx *ctx)
+{
+ SHA384_Init((SHA512_CTX *) ctx);
+}
+
+void
+pg_sha384_update(pg_sha384_ctx *ctx, const uint8 *data, size_t len)
+{
+ SHA384_Update((SHA512_CTX *) ctx, data, len);
+}
+
+void
+pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest)
+{
+ SHA384_Final(dest, (SHA512_CTX *) ctx);
+}
+
+/* Interface routines for SHA-224 */
+void
+pg_sha224_init(pg_sha224_ctx *ctx)
+{
+ SHA224_Init((SHA256_CTX *) ctx);
+}
+
+void
+pg_sha224_update(pg_sha224_ctx *ctx, const uint8 *data, size_t len)
+{
+ SHA224_Update((SHA256_CTX *) ctx, data, len);
+}
+
+void
+pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest)
+{
+ SHA224_Final(dest, (SHA256_CTX *) ctx);
+}
diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h
new file mode 100644
index 0000000000..015a9053ac
--- /dev/null
+++ b/src/include/common/sha2.h
@@ -0,0 +1,115 @@
+/*-------------------------------------------------------------------------
+ *
+ * sha2.h
+ * Generic headers for SHA224, 256, 384 AND 512 functions of PostgreSQL.
+ *
+ * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/include/common/sha2.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */
+
+/*
+ * FILE: sha2.h
+ * AUTHOR: Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
+ */
+
+#ifndef _PG_SHA2_H_
+#define _PG_SHA2_H_
+
+#ifdef USE_SSL
+#include <openssl/sha.h>
+#endif
+
+/*** SHA224/256/384/512 Various Length Definitions ***********************/
+#define PG_SHA224_BLOCK_LENGTH 64
+#define PG_SHA224_DIGEST_LENGTH 28
+#define PG_SHA224_DIGEST_STRING_LENGTH (PG_SHA224_DIGEST_LENGTH * 2 + 1)
+#define PG_SHA256_BLOCK_LENGTH 64
+#define PG_SHA256_DIGEST_LENGTH 32
+#define PG_SHA256_DIGEST_STRING_LENGTH (PG_SHA256_DIGEST_LENGTH * 2 + 1)
+#define PG_SHA384_BLOCK_LENGTH 128
+#define PG_SHA384_DIGEST_LENGTH 48
+#define PG_SHA384_DIGEST_STRING_LENGTH (PG_SHA384_DIGEST_LENGTH * 2 + 1)
+#define PG_SHA512_BLOCK_LENGTH 128
+#define PG_SHA512_DIGEST_LENGTH 64
+#define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1)
+
+/* Context Structures for SHA-1/224/256/384/512 */
+#ifdef USE_SSL
+typedef SHA256_CTX pg_sha256_ctx;
+typedef SHA512_CTX pg_sha512_ctx;
+typedef SHA256_CTX pg_sha224_ctx;
+typedef SHA512_CTX pg_sha384_ctx;
+#else
+typedef struct pg_sha256_ctx
+{
+ uint32 state[8];
+ uint64 bitcount;
+ uint8 buffer[PG_SHA256_BLOCK_LENGTH];
+} pg_sha256_ctx;
+typedef struct pg_sha512_ctx
+{
+ uint64 state[8];
+ uint64 bitcount[2];
+ uint8 buffer[PG_SHA512_BLOCK_LENGTH];
+} pg_sha512_ctx;
+typedef struct pg_sha256_ctx pg_sha224_ctx;
+typedef struct pg_sha512_ctx pg_sha384_ctx;
+#endif /* USE_SSL */
+
+/* Interface routines for SHA224/256/384/512 */
+extern void pg_sha224_init(pg_sha224_ctx *ctx);
+extern void pg_sha224_update(pg_sha224_ctx *ctx,
+ const uint8 *input0, size_t len);
+extern void pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest);
+
+extern void pg_sha256_init(pg_sha256_ctx *ctx);
+extern void pg_sha256_update(pg_sha256_ctx *ctx,
+ const uint8 *input0, size_t len);
+extern void pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest);
+
+extern void pg_sha384_init(pg_sha384_ctx *ctx);
+extern void pg_sha384_update(pg_sha384_ctx *ctx,
+ const uint8 *, size_t len);
+extern void pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest);
+
+extern void pg_sha512_init(pg_sha512_ctx *ctx);
+extern void pg_sha512_update(pg_sha512_ctx *ctx,
+ const uint8 *input0, size_t len);
+extern void pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest);
+
+#endif /* _PG_SHA2_H_ */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 51b5d5449a..2824711767 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -114,6 +114,15 @@ sub mkvcbuild
md5.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
string.c username.c wait_error.c);
+ if ($solution->{options}->{openssl})
+ {
+ push(@pgcommonallfiles, 'sha2_openssl.c');
+ }
+ else
+ {
+ push(@pgcommonallfiles, 'sha2.c');
+ }
+
our @pgcommonfrontendfiles = (
@pgcommonallfiles, qw(fe_memutils.c file_utils.c
restricted_token.c));
@@ -421,13 +430,14 @@ sub mkvcbuild
else
{
$pgcrypto->AddFiles(
- 'contrib/pgcrypto', 'md5.c',
- 'sha1.c', 'sha2.c',
- 'internal.c', 'internal-sha2.c',
- 'blf.c', 'rijndael.c',
- 'pgp-mpi-internal.c', 'imath.c');
+ 'contrib/pgcrypto', 'md5.c',
+ 'sha1.c', 'internal.c',
+ 'internal-sha2.c', 'blf.c',
+ 'rijndael.c', 'pgp-mpi-internal.c',
+ 'imath.c');
}
$pgcrypto->AddReference($postgres);
+ $pgcrypto->AddReference($libpgcommon);
$pgcrypto->AddLibrary('ws2_32.lib');
my $mf = Project::read_file('contrib/pgcrypto/Makefile');
GenerateContribSqlFiles('pgcrypto', $mf);
--
2.12.0
0002-Add-encoding-routines-for-base64-without-whitespace-.patchapplication/octet-stream; name=0002-Add-encoding-routines-for-base64-without-whitespace-.patchDownload
From df376426c9d199187b8c697dd5837bed7e21f770 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Tue, 18 Oct 2016 15:28:45 +0900
Subject: [PATCH 2/8] Add encoding routines for base64 without whitespace in
src/common/
Those routines are taken from the backend's encode.c, and adapted for
SCRAM-SHA-256, where base64 should not support whitespaces as per RFC5802.
---
src/common/Makefile | 6 +-
src/common/base64.c | 201 ++++++++++++++++++++++++++++++++++++++++++++
src/include/common/base64.h | 19 +++++
src/tools/msvc/Mkvcbuild.pm | 2 +-
4 files changed, 224 insertions(+), 4 deletions(-)
create mode 100644 src/common/base64.c
create mode 100644 src/include/common/base64.h
diff --git a/src/common/Makefile b/src/common/Makefile
index 5ddfff8b44..49e41cf846 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -40,9 +40,9 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\""
override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
-OBJS_COMMON = config_info.o controldata_utils.o exec.o ip.o keywords.o \
- md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \
- string.o username.o wait_error.o
+OBJS_COMMON = base64.o config_info.o controldata_utils.o exec.o ip.o \
+ keywords.o md5.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o \
+ rmtree.o string.o username.o wait_error.o
ifeq ($(with_openssl),yes)
OBJS_COMMON += sha2_openssl.o
diff --git a/src/common/base64.c b/src/common/base64.c
new file mode 100644
index 0000000000..0c9eba45b6
--- /dev/null
+++ b/src/common/base64.c
@@ -0,0 +1,201 @@
+/*-------------------------------------------------------------------------
+ *
+ * base64.c
+ * Set of encoding and decoding routines for base64 without support
+ * for whitespace. In case of failure, those routines return -1 in case
+ * of error to let the caller do any error handling.
+ *
+ * Copyright (c) 2001-2016, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/common/base64.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/base64.h"
+
+/*
+ * BASE64
+ */
+
+static const char _base64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const int8 b64lookup[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+};
+
+/*
+ * pg_b64_encode
+ *
+ * Encode into base64 the given string. Returns the length of the encoded
+ * string on success, and -1 in the event of an error.
+ */
+int
+pg_b64_encode(const char *src, int len, char *dst)
+{
+ char *p;
+ const char *s,
+ *end = src + len;
+ int pos = 2;
+ uint32 buf = 0;
+
+ s = src;
+ p = dst;
+
+ while (s < end)
+ {
+ buf |= (unsigned char) *s << (pos << 3);
+ pos--;
+ s++;
+
+ /* write it out */
+ if (pos < 0)
+ {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = _base64[(buf >> 6) & 0x3f];
+ *p++ = _base64[buf & 0x3f];
+
+ pos = 2;
+ buf = 0;
+ }
+ }
+ if (pos != 2)
+ {
+ *p++ = _base64[(buf >> 18) & 0x3f];
+ *p++ = _base64[(buf >> 12) & 0x3f];
+ *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
+ *p++ = '=';
+ }
+
+ return p - dst;
+}
+
+/*
+ * pg_b64_decode
+ *
+ * Decode the given base64 string. Returns the length of the decoded
+ * string on success, and -1 in the event of an error.
+ */
+int
+pg_b64_decode(const char *src, int len, char *dst)
+{
+ const char *srcend = src + len,
+ *s = src;
+ char *p = dst;
+ char c;
+ int b = 0;
+ uint32 buf = 0;
+ int pos = 0,
+ end = 0;
+
+ while (s < srcend)
+ {
+ c = *s++;
+
+ /* Leave if a whitespace is found */
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ return -1;
+
+ if (c == '=')
+ {
+ /* end sequence */
+ if (!end)
+ {
+ if (pos == 2)
+ end = 1;
+ else if (pos == 3)
+ end = 2;
+ else
+ {
+ /*
+ * Unexpected "=" character found while decoding base64
+ * sequence.
+ */
+ return -1;
+ }
+ }
+ b = 0;
+ }
+ else
+ {
+ b = -1;
+ if (c > 0 && c < 127)
+ b = b64lookup[(unsigned char) c];
+ if (b < 0)
+ {
+ /* invalid symbol found */
+ return -1;
+ }
+ }
+ /* add it to buffer */
+ buf = (buf << 6) + b;
+ pos++;
+ if (pos == 4)
+ {
+ *p++ = (buf >> 16) & 255;
+ if (end == 0 || end > 1)
+ *p++ = (buf >> 8) & 255;
+ if (end == 0 || end > 2)
+ *p++ = buf & 255;
+ buf = 0;
+ pos = 0;
+ }
+ }
+
+ if (pos != 0)
+ {
+ /*
+ * base64 end sequence is invalid. Input data is missing padding,
+ * is truncated or is otherwise corrupted.
+ */
+ return -1;
+ }
+
+ return p - dst;
+}
+
+/*
+ * pg_b64_enc_len
+ *
+ * Returns to caller the length of the string if it were encoded with
+ * base64 based on the length provided by caller. This is useful to
+ * estimate how large a buffer allocation needs to be done before doing
+ * the actual encoding.
+ */
+int
+pg_b64_enc_len(int srclen)
+{
+ /* 3 bytes will be converted to 4 */
+ return (srclen + 2) * 4 / 3;
+}
+
+/*
+ * pg_b64_dec_len
+ *
+ * Returns to caller the length of the string if it were to be decoded
+ * with base64, based on the length given by caller. This is useful to
+ * estimate how large a buffer allocation needs to be done before doing
+ * the actual decoding.
+ */
+int
+pg_b64_dec_len(int srclen)
+{
+ return (srclen * 3) >> 2;
+}
diff --git a/src/include/common/base64.h b/src/include/common/base64.h
new file mode 100644
index 0000000000..8ad8eb6f62
--- /dev/null
+++ b/src/include/common/base64.h
@@ -0,0 +1,19 @@
+/*
+ * base64.h
+ * Encoding and decoding routines for base64 without whitespace
+ * support.
+ *
+ * Portions Copyright (c) 2001-2016, PostgreSQL Global Development Group
+ *
+ * src/include/common/base64.h
+ */
+#ifndef BASE64_H
+#define BASE64_H
+
+/* base 64 */
+int pg_b64_encode(const char *src, int len, char *dst);
+int pg_b64_decode(const char *src, int len, char *dst);
+int pg_b64_enc_len(int srclen);
+int pg_b64_dec_len(int srclen);
+
+#endif /* BASE64_H */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 2824711767..49743aba1e 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -110,7 +110,7 @@ sub mkvcbuild
}
our @pgcommonallfiles = qw(
- config_info.c controldata_utils.c exec.c ip.c keywords.c
+ base64.c config_info.c controldata_utils.c exec.c ip.c keywords.c
md5.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
string.c username.c wait_error.c);
--
2.12.0
0003-Add-clause-PASSWORD-val-USING-protocol-to-CREATE-ALT.patchapplication/octet-stream; name=0003-Add-clause-PASSWORD-val-USING-protocol-to-CREATE-ALT.patchDownload
From 48d9e4dda4a454c2bc3d909922a8374da52340cb Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 14 Nov 2016 18:24:10 +0900
Subject: [PATCH 3/8] Add clause PASSWORD (val USING protocol) to CREATE/ALTER
ROLE
This clause allows users to be able to enforce with which protocol
a given password is used with. if the value given is already encrypted,
the value is used as-is. This extension is useful to support future
protocols, particularly SCRAM-SHA-256.
---
doc/src/sgml/ref/alter_role.sgml | 10 +++++
doc/src/sgml/ref/create_role.sgml | 26 +++++++++++
src/backend/commands/user.c | 90 ++++++++++++++++++++++++++++++++++++---
src/backend/parser/gram.y | 7 +++
4 files changed, 126 insertions(+), 7 deletions(-)
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml
index da36ad9696..43e45d504d 100644
--- a/doc/src/sgml/ref/alter_role.sgml
+++ b/doc/src/sgml/ref/alter_role.sgml
@@ -34,6 +34,7 @@ ALTER ROLE <replaceable class="PARAMETER">role_specification</replaceable> [ WIT
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+ | PASSWORD ( '<replaceable class="PARAMETER">password</replaceable>' USING '<replaceable class="PARAMETER">method</replaceable>' )
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
@@ -169,6 +170,7 @@ ALTER ROLE { <replaceable class="PARAMETER">role_specification</replaceable> | A
<term><literal>NOBYPASSRLS</literal></term>
<term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term>
<term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
+ <term><literal>PASSWORD</> ( '<replaceable class="parameter">password</replaceable>' USING '<replaceable class="parameter">method</replaceable>' )</term>
<term><literal>ENCRYPTED</></term>
<term><literal>UNENCRYPTED</></term>
<term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term>
@@ -280,6 +282,14 @@ ALTER ROLE davide WITH PASSWORD 'hu8jmn3';
</para>
<para>
+ Change a role's password using MD5-encryption:
+
+<programlisting>
+ALTER ROLE lionel WITH PASSWORD ('hu8jmn3' USING 'md5');
+</programlisting>
+ </para>
+
+ <para>
Remove a role's password:
<programlisting>
diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml
index 2ae576ede6..be87a211c8 100644
--- a/doc/src/sgml/ref/create_role.sgml
+++ b/doc/src/sgml/ref/create_role.sgml
@@ -34,6 +34,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+ | PASSWORD ( '<replaceable class="PARAMETER">password</replaceable>' USING '<replaceable class="PARAMETER">method</replaceable>' )
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
| IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
| IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]
@@ -242,6 +243,23 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
</varlistentry>
<varlistentry>
+ <term><literal>PASSWORD</> ( '<replaceable class="parameter">password</replaceable>' USING '<replaceable class="parameter">method</replaceable>' )</term>
+ <listitem>
+ <para>
+ Sets the role's password using the requested method. (A password
+ is only of use for roles having the <literal>LOGIN</literal>
+ attribute, but you can nonetheless define one for roles without it.)
+ If you do not plan to use password authentication you can omit this
+ option. The methods supported are <literal>md5</> to enforce
+ a password to be MD5-encrypted, and <literal>plain</> to use an
+ unencrypted password. If the password string is already in
+ MD5-encrypted format, then it is stored encrypted even if
+ <literal>plain</> is specified.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term>
<listitem>
<para>
@@ -423,6 +441,14 @@ CREATE USER davide WITH PASSWORD 'jw8s0F4';
</para>
<para>
+ Create a role with a MD5-encrypted password:
+
+<programlisting>
+CREATE USER lionel WITH PASSWORD ('asdh7as' USING 'md5');
+</programlisting>
+ </para>
+
+ <para>
Create a role with a password that is valid until the end of 2004.
After one second has ticked in 2005, the password is no longer
valid.
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 994c093250..6fca7e16bd 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -130,7 +130,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
if (strcmp(defel->defname, "password") == 0 ||
strcmp(defel->defname, "encryptedPassword") == 0 ||
- strcmp(defel->defname, "unencryptedPassword") == 0)
+ strcmp(defel->defname, "unencryptedPassword") == 0 ||
+ strcmp(defel->defname, "methodPassword") == 0)
{
if (dpassword)
ereport(ERROR,
@@ -138,10 +139,49 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
dpassword = defel;
- if (strcmp(defel->defname, "encryptedPassword") == 0)
+ if (strcmp(defel->defname, "password") == 0)
+ {
+ /*
+ * Password type is enforced with GUC password_encryption
+ * here.
+ */
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
+ else if (strcmp(defel->defname, "encryptedPassword") == 0)
+ {
password_type = PASSWORD_TYPE_MD5;
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
+ {
password_type = PASSWORD_TYPE_PLAINTEXT;
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
+ else if (strcmp(defel->defname, "methodPassword") == 0)
+ {
+ /*
+ * This is a list of two elements, the password is first and
+ * then there is the method wanted by caller.
+ */
+ if (dpassword && dpassword->arg)
+ {
+ char *method = strVal(lsecond((List *) dpassword->arg));
+
+ password = strVal(linitial((List *) dpassword->arg));
+
+ if (strcmp(method, "md5") == 0)
+ password_type = PASSWORD_TYPE_MD5;
+ else if (strcmp(method, "plain") == 0)
+ password_type = PASSWORD_TYPE_PLAINTEXT;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unsupported password method %s", method)));
+ }
+ }
}
else if (strcmp(defel->defname, "sysid") == 0)
{
@@ -261,8 +301,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
defel->defname);
}
- if (dpassword && dpassword->arg)
- password = strVal(dpassword->arg);
if (dissuper)
issuper = intVal(dissuper->arg) != 0;
if (dinherit)
@@ -534,6 +572,7 @@ AlterRole(AlterRoleStmt *stmt)
if (strcmp(defel->defname, "password") == 0 ||
strcmp(defel->defname, "encryptedPassword") == 0 ||
+ strcmp(defel->defname, "methodPassword") == 0 ||
strcmp(defel->defname, "unencryptedPassword") == 0)
{
if (dpassword)
@@ -541,10 +580,49 @@ AlterRole(AlterRoleStmt *stmt)
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
dpassword = defel;
- if (strcmp(defel->defname, "encryptedPassword") == 0)
+ if (strcmp(defel->defname, "password") == 0)
+ {
+ /*
+ * Password type is enforced with GUC password_encryption
+ * here.
+ */
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
+ else if (strcmp(defel->defname, "encryptedPassword") == 0)
+ {
password_type = PASSWORD_TYPE_MD5;
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
+ {
password_type = PASSWORD_TYPE_PLAINTEXT;
+ if (dpassword && dpassword->arg)
+ password = strVal(dpassword->arg);
+ }
+ else if (strcmp(defel->defname, "methodPassword") == 0)
+ {
+ /*
+ * This is a list of two elements, the password is first and
+ * then there is the method wanted by caller.
+ */
+ if (dpassword && dpassword->arg)
+ {
+ char *method = strVal(lsecond((List *) dpassword->arg));
+
+ if (strcmp(method, "md5") == 0)
+ password_type = PASSWORD_TYPE_MD5;
+ else if (strcmp(method, "plain") == 0)
+ password_type = PASSWORD_TYPE_PLAINTEXT;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unsupported password method %s", method)));
+
+ password = strVal(linitial((List *) dpassword->arg));
+ }
+ }
}
else if (strcmp(defel->defname, "superuser") == 0)
{
@@ -632,8 +710,6 @@ AlterRole(AlterRoleStmt *stmt)
defel->defname);
}
- if (dpassword && dpassword->arg)
- password = strVal(dpassword->arg);
if (dissuper)
issuper = intVal(dissuper->arg);
if (dinherit)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e833b2eba5..c519128389 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -987,6 +987,13 @@ AlterOptRoleElem:
{
$$ = makeDefElem("password", NULL, @1);
}
+ | PASSWORD '(' Sconst USING Sconst ')'
+ {
+ $$ = makeDefElem("methodPassword",
+ (Node *)list_make2(makeString($3),
+ makeString($5)),
+ @1);
+ }
| ENCRYPTED PASSWORD Sconst
{
$$ = makeDefElem("encryptedPassword",
--
2.12.0
0005-Add-regression-tests-for-passwords.patchapplication/octet-stream; name=0005-Add-regression-tests-for-passwords.patchDownload
From 38ce08d9fc21313745d5e77bbdf0e6aee0d67eb6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 14 Nov 2016 19:45:35 +0900
Subject: [PATCH 5/8] Add regression tests for passwords
---
src/test/regress/expected/password.out | 108 +++++++++++++++++++++++++++++++++
src/test/regress/parallel_schedule | 2 +-
src/test/regress/serial_schedule | 1 +
src/test/regress/sql/password.sql | 76 +++++++++++++++++++++++
4 files changed, 186 insertions(+), 1 deletion(-)
create mode 100644 src/test/regress/expected/password.out
create mode 100644 src/test/regress/sql/password.sql
diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out
new file mode 100644
index 0000000000..eff3127cd1
--- /dev/null
+++ b/src/test/regress/expected/password.out
@@ -0,0 +1,108 @@
+--
+-- Tests for password verifiers
+--
+-- Tests for GUC password_encryption
+SET password_encryption = 'novalue'; -- error
+ERROR: invalid value for parameter "password_encryption": "novalue"
+HINT: Available values: plain, md5, scram, off, on.
+SET password_encryption = true; -- ok
+SET password_encryption = 'md5'; -- ok
+SET password_encryption = 'plain'; -- ok
+SET password_encryption = 'scram'; -- ok
+-- consistency of password entries
+SET password_encryption = 'plain';
+CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
+SET password_encryption = 'md5';
+CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+SET password_encryption = 'on';
+CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
+SET password_encryption = 'scram';
+CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4';
+SET password_encryption = 'plain';
+CREATE ROLE regress_passwd5 PASSWORD NULL;
+-- check list of created entries
+--
+-- The scram verifier will look something like:
+-- scram-sha-256:E4HxLGtnRzsYwg==:4096:5ebc825510cb7862efd87dfa638d8337179e6913a724441dc9e888a856fbc10c:e966b1c72fad89d69aaebb156eae04edc9581286f92207c044711e79cd461bee
+--
+-- Since the salt is random, the exact value stored will be different on every test
+-- run. Use a regular expression to mask the changing parts.
+SELECT rolname, regexp_replace(rolpassword, '(scram-sha-256):([a-zA-Z0-9+/]+==):(\d+):(\w+):(\w+)', '\1:<salt>:\3:<storedkey>:<serverkey>') as rolpassword_masked
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+ rolname | rolpassword_masked
+-----------------+---------------------------------------------------
+ regress_passwd1 | role_pwd1
+ regress_passwd2 | md54044304ba511dd062133eb5b4b84a2a3
+ regress_passwd3 | md50e5699b6911d87f17a08b8d76a21e8b8
+ regress_passwd4 | scram-sha-256:<salt>:4096:<storedkey>:<serverkey>
+ regress_passwd5 |
+(5 rows)
+
+-- Rename a role
+ALTER ROLE regress_passwd3 RENAME TO regress_passwd3_new;
+NOTICE: MD5 password cleared because of role rename
+-- md5 entry should have been removed
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd3_new'
+ ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+---------------------+-------------
+ regress_passwd3_new |
+(1 row)
+
+ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3;
+-- ENCRYPTED and UNENCRYPTED passwords
+ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted
+ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5deaeed29b1cf796ea981d53e82cd5856'; -- encrypted with MD5
+ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5
+ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'md5deaeed29b1cf796ea981d53e82cd5856'; -- encrypted with MD5
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+-----------------+-------------------------------------
+ regress_passwd1 | foo
+ regress_passwd2 | md5deaeed29b1cf796ea981d53e82cd5856
+ regress_passwd3 | md5530de4c298af94b3b9f7d20305d2a1bf
+ regress_passwd4 | md5deaeed29b1cf796ea981d53e82cd5856
+ regress_passwd5 |
+(5 rows)
+
+-- PASSWORD val USING protocol
+ALTER ROLE regress_passwd1 PASSWORD ('foo' USING 'non_existent');
+ERROR: unsupported password method non_existent
+ALTER ROLE regress_passwd1 PASSWORD ('md5deaeed29b1cf796ea981d53e82cd5856' USING 'plain'); -- ok, as md5
+ALTER ROLE regress_passwd2 PASSWORD ('foo' USING 'plain'); -- ok, as plain
+ALTER ROLE regress_passwd3 PASSWORD ('md5deaeed29b1cf796ea981d53e82cd5856' USING 'scram'); -- ok, as md5
+ALTER ROLE regress_passwd4 PASSWORD ('scram-sha-256:kfSJjF3tdoxDNA==:4096:c52173111c7354ca17c66ba570e230ccec51c15c9f510b998d28297f723af5fa:a55cacd2a24bc2673c3d4266b8b90fa58231a674ae1b08e02236beba283fc2d5' USING 'plain'); -- ok, as scram
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ regress_passwd1 | md5deaeed29b1cf796ea981d53e82cd5856
+ regress_passwd2 | foo
+ regress_passwd3 | md5deaeed29b1cf796ea981d53e82cd5856
+ regress_passwd4 | scram-sha-256:kfSJjF3tdoxDNA==:4096:c52173111c7354ca17c66ba570e230ccec51c15c9f510b998d28297f723af5fa:a55cacd2a24bc2673c3d4266b8b90fa58231a674ae1b08e02236beba283fc2d5
+ regress_passwd5 |
+(5 rows)
+
+DROP ROLE regress_passwd1;
+DROP ROLE regress_passwd2;
+DROP ROLE regress_passwd3;
+DROP ROLE regress_passwd4;
+DROP ROLE regress_passwd5;
+-- all entries should have been removed
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+---------+-------------
+(0 rows)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index edeb2d6bc7..15d43ba9a6 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: select_into select_distinct select_distinct_on select_implicit select_havi
# ----------
# Another group of parallel tests
# ----------
-test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator
+test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator password
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 27a46d76d5..8855d21dcd 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -112,6 +112,7 @@ test: matview
test: lock
test: replica_identity
test: rowsecurity
+test: password
test: object_address
test: tablesample
test: groupingsets
diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql
new file mode 100644
index 0000000000..196b019270
--- /dev/null
+++ b/src/test/regress/sql/password.sql
@@ -0,0 +1,76 @@
+--
+-- Tests for password verifiers
+--
+
+-- Tests for GUC password_encryption
+SET password_encryption = 'novalue'; -- error
+SET password_encryption = true; -- ok
+SET password_encryption = 'md5'; -- ok
+SET password_encryption = 'plain'; -- ok
+SET password_encryption = 'scram'; -- ok
+
+-- consistency of password entries
+SET password_encryption = 'plain';
+CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
+SET password_encryption = 'md5';
+CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+SET password_encryption = 'on';
+CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
+SET password_encryption = 'scram';
+CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4';
+SET password_encryption = 'plain';
+CREATE ROLE regress_passwd5 PASSWORD NULL;
+
+-- check list of created entries
+--
+-- The scram verifier will look something like:
+-- scram-sha-256:E4HxLGtnRzsYwg==:4096:5ebc825510cb7862efd87dfa638d8337179e6913a724441dc9e888a856fbc10c:e966b1c72fad89d69aaebb156eae04edc9581286f92207c044711e79cd461bee
+--
+-- Since the salt is random, the exact value stored will be different on every test
+-- run. Use a regular expression to mask the changing parts.
+SELECT rolname, regexp_replace(rolpassword, '(scram-sha-256):([a-zA-Z0-9+/]+==):(\d+):(\w+):(\w+)', '\1:<salt>:\3:<storedkey>:<serverkey>') as rolpassword_masked
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+
+-- Rename a role
+ALTER ROLE regress_passwd3 RENAME TO regress_passwd3_new;
+-- md5 entry should have been removed
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd3_new'
+ ORDER BY rolname, rolpassword;
+ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3;
+
+-- ENCRYPTED and UNENCRYPTED passwords
+ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted
+ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5deaeed29b1cf796ea981d53e82cd5856'; -- encrypted with MD5
+ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5
+ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'md5deaeed29b1cf796ea981d53e82cd5856'; -- encrypted with MD5
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+
+-- PASSWORD val USING protocol
+ALTER ROLE regress_passwd1 PASSWORD ('foo' USING 'non_existent');
+ALTER ROLE regress_passwd1 PASSWORD ('md5deaeed29b1cf796ea981d53e82cd5856' USING 'plain'); -- ok, as md5
+ALTER ROLE regress_passwd2 PASSWORD ('foo' USING 'plain'); -- ok, as plain
+ALTER ROLE regress_passwd3 PASSWORD ('md5deaeed29b1cf796ea981d53e82cd5856' USING 'scram'); -- ok, as md5
+ALTER ROLE regress_passwd4 PASSWORD ('scram-sha-256:kfSJjF3tdoxDNA==:4096:c52173111c7354ca17c66ba570e230ccec51c15c9f510b998d28297f723af5fa:a55cacd2a24bc2673c3d4266b8b90fa58231a674ae1b08e02236beba283fc2d5' USING 'plain'); -- ok, as scram
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
+
+DROP ROLE regress_passwd1;
+DROP ROLE regress_passwd2;
+DROP ROLE regress_passwd3;
+DROP ROLE regress_passwd4;
+DROP ROLE regress_passwd5;
+
+-- all entries should have been removed
+SELECT rolname, rolpassword
+ FROM pg_authid
+ WHERE rolname LIKE 'regress_passwd%'
+ ORDER BY rolname, rolpassword;
--
2.12.0
0006-Add-TAP-tests-for-authentication-methods.patchapplication/octet-stream; name=0006-Add-TAP-tests-for-authentication-methods.patchDownload
From 5bcf156730084b1ab8504af90af581dae98c4c3b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 2 Mar 2017 15:44:06 +0900
Subject: [PATCH 6/8] Add TAP tests for authentication methods
Those are useful to test what is expected from users having either plain,
MD5-encrypted or SCRAM passwords.
---
src/test/recovery/t/010_authentication.pl | 85 +++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 src/test/recovery/t/010_authentication.pl
diff --git a/src/test/recovery/t/010_authentication.pl b/src/test/recovery/t/010_authentication.pl
new file mode 100644
index 0000000000..16be7f5cc8
--- /dev/null
+++ b/src/test/recovery/t/010_authentication.pl
@@ -0,0 +1,85 @@
+# Set of tests for authentication and pg_hba.conf. The following password
+# methods are checked through this test:
+# - Plain
+# - MD5-encrypted
+# - SCRAM-encrypted
+# This test cannot run on Windows as Postgres cannot be set up with Unix
+# sockets and needs to go through SSPI.
+
+use strict;
+use warnings;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 12;
+
+# Delete pg_hba.conf from the given node, add a new entry to it
+# and then execute a reload to refresh it.
+sub reset_pg_hba
+{
+ my $node = shift;
+ my $hba_method = shift;
+
+ unlink($node->data_dir . '/pg_hba.conf');
+ $node->append_conf('pg_hba.conf', "local all all $hba_method");
+ $node->reload;
+}
+
+# Test access for a single role, useful to wrap all tests into one.
+sub test_role
+{
+ my $node = shift;
+ my $role = shift;
+ my $method = shift;
+ my $expected_res = shift;
+ my $status_string = 'failed';
+
+ $status_string = 'success' if ($expected_res eq 0);
+
+ my $res = $node->psql('postgres', 'SELECT 1', extra_params => ['-U', $role]);
+ is($res, $expected_res,
+ "authentication $status_string for method $method, role $role");
+}
+
+SKIP:
+{
+ skip "authentication tests cannot run on Windows", 12 if ($windows_os);
+
+ # Initialize master node
+ my $node = get_new_node('master');
+ $node->init;
+ $node->start;
+
+ # Create 3 roles with different password methods for each one. The same
+ # password is used for all of them.
+ $node->safe_psql('postgres', "CREATE ROLE scram_role LOGIN PASSWORD ('pass' USING 'scram');");
+ $node->safe_psql('postgres', "CREATE ROLE md5_role LOGIN PASSWORD ('pass' USING 'md5');");
+ $node->safe_psql('postgres', "CREATE ROLE plain_role LOGIN PASSWORD ('pass' USING 'plain');");
+ $ENV{"PGPASSWORD"} = 'pass';
+
+ # For "trust" method, all users should be able to connect.
+ reset_pg_hba($node, 'trust');
+ test_role($node, 'scram_role', 'trust', 0);
+ test_role($node, 'md5_role', 'trust', 0);
+ test_role($node, 'plain_role', 'trust', 0);
+
+ # For "plain" method, users "plain_role" and "md5_role" should be able to
+ # connect.
+ reset_pg_hba($node, 'password');
+ test_role($node, 'scram_role', 'password', 2);
+ test_role($node, 'md5_role', 'password', 0);
+ test_role($node, 'plain_role', 'password', 0);
+
+ # For "scram" method, user "plain_role" and "scram_role" should be able to
+ # connect.
+ reset_pg_hba($node, 'scram');
+ test_role($node, 'scram_role', 'scram', 0);
+ test_role($node, 'md5_role', 'scram', 2);
+ test_role($node, 'plain_role', 'scram', 0);
+
+ # For "md5" method, users "plain_role" and "md5_role" should be able to
+ # connect.
+ reset_pg_hba($node, 'md5');
+ test_role($node, 'scram_role', 'md5', 2);
+ test_role($node, 'md5_role', 'md5', 0);
+ test_role($node, 'plain_role', 'md5', 0);
+}
--
2.12.0
0007-Make-hba-configuration-for-SASL-more-extensible.patchapplication/octet-stream; name=0007-Make-hba-configuration-for-SASL-more-extensible.patchDownload
From 6f00620dd2029b5f6777c1478edd31002834524b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 20 Feb 2017 14:15:18 +0900
Subject: [PATCH 7/8] Make hba configuration for SASL more extensible
The entries of pg_hba.conf are changed from "scram" to that:
"sasl protocol=scram_sha_256". SASL supporting many families of
authentication mechanisms, this likely makes the most sense. protocol
is as well a mandatory parameter. In the future if other mechanisms
are added this will prove to be very handy, by being able for example
to have a list of mechanisms defined.
Documentation and regression tests are updated according to that.
---
doc/src/sgml/client-auth.sgml | 46 +++++++++++++++++++++++--------
src/backend/libpq/auth.c | 10 +++++--
src/backend/libpq/hba.c | 31 +++++++++++++++++++--
src/backend/libpq/pg_hba.conf.sample | 4 +--
src/bin/initdb/initdb.c | 14 +++++-----
src/include/libpq/hba.h | 1 +
src/test/recovery/t/010_authentication.pl | 14 +++++++---
7 files changed, 91 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index f27d417f65..125a07325a 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -423,11 +423,12 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</varlistentry>
<varlistentry>
- <term><literal>scram</></term>
+ <term><literal>sasl</></term>
<listitem>
<para>
Require the client to supply a password encrypted with
- SCRAM-SHA-256 for authentication.
+ a protocol compatible with SASL exchange protocol, like
+ SCRAM-SHA-256, for authentication.
See <xref linkend="auth-password"> for details.
</para>
</listitem>
@@ -684,19 +685,19 @@ host postgres all 192.168.93.0/24 ident
# "postgres" if the user's password is correctly supplied.
#
# TYPE DATABASE USER ADDRESS METHOD
-host postgres all 192.168.12.10/32 scram
+host postgres all 192.168.12.10/32 sasl protocol=scram_sha_256
# Allow any user from hosts in the example.com domain to connect to
# any database if the user's password is correctly supplied.
#
-# Most users use SCRAM authentication, but some users use older clients
-# that don't support SCRAM authentication, and need to be able to log
-# in using MD5 authentication. Such users are put in the @md5users
-# group, everyone else must use SCRAM.
+# Most users use SCRAM-SHA-256 authentication, but some users use older
+# clients that don't support SCRAM-SHA-256 authentication, and need to be
+# able to log in using MD5 authentication. Such users are put in the @md5users
+# group, everyone else must use SCRAM-SHA-256.
#
# TYPE DATABASE USER ADDRESS METHOD
host all @md5users .example.com md5
-host all all .example.com scram
+host all all .example.com sasl protocol=scram_sha_256
# In the absence of preceding "host" lines, these two lines will
# reject all connections from 192.168.54.1 (since that entry will be
@@ -942,8 +943,8 @@ omicron bryanh guest1
</para>
<para>
- <literal>scram</>, as described in
- <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink> is
+ <literal>sasl</>, as described in
+ <ulink url="https://tools.ietf.org/html/rfc4422">RFC4422</ulink> is
defined to be more robust more than <literal>md5</> from a security
point of view as it protects from cases where the hashed password is
taken directly from <structname>pg_authid</structname> in which case
@@ -951,8 +952,29 @@ omicron bryanh guest1
the password behind it. It protects as well from password interception
and data sniffing where the password data could be directly obtained
from the network as well as man-in-the-middle (MITM) attacks. So it
- is strongly encouraged to use <literal>scram</> over <literal>md5</> for
- password-based deployments.
+ is strongly encouraged to use <literal>sasl</> over <literal>md5</> for
+ password-based deployments. <productname>SASL</> supports many families
+ of authentication mechanisms, <productname>PostgreSQL</> supporting only
+ <literal>SCRAM-SHA-256</literal> as described in
+ <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink>.
+ </para>
+
+ <para>
+ The following configuration options are supported for <productname>SASL</productname>:
+ <variablelist>
+ <varlistentry>
+ <term><literal>protocol</literal></term>
+ <listitem>
+ <para>
+ Sets the exchange protocol supported. This parameter is mandatory
+ and only the authentication mechanism listed are supported for the
+ user attempting a connection. It can be to <literal>scram_sha_256</>
+ to authorize users to connect using <literal>SCRAM-SHA-256</literal>
+ as authentication mechanism for the SASL exchange protocol.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</para>
<para>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index e475366ef3..2adfb8c4d4 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -818,8 +818,14 @@ CheckSASLAuth(Port *port, char **logdetail)
* guess that a server is expecting SASL or MD5 depending on the answer
* given by the backend without the user providing a password first.
*/
- sendAuthRequest(port, AUTH_REQ_SASL, SCRAM_SHA256_NAME,
- strlen(SCRAM_SHA256_NAME) + 1);
+ if (strcmp(port->hba->sasl_protocol, "scram_sha_256") == 0)
+ sendAuthRequest(port, AUTH_REQ_SASL, SCRAM_SHA256_NAME,
+ strlen(SCRAM_SHA256_NAME) + 1);
+ else
+ ereport(FATAL,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SASL protocol %s is not supported",
+ port->hba->sasl_protocol)));
/*
* If the user doesn't exist, or doesn't have a valid password, or
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 3817d249c4..b060109f93 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -125,7 +125,7 @@ static const char *const UserAuthName[] =
"ident",
"password",
"md5",
- "scram",
+ "sasl",
"gss",
"sspi",
"pam",
@@ -1324,7 +1324,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
}
parsedline->auth_method = uaMD5;
}
- else if (strcmp(token->string, "scram") == 0)
+ else if (strcmp(token->string, "sasl") == 0)
parsedline->auth_method = uaSASL;
else if (strcmp(token->string, "pam") == 0)
#ifdef USE_PAM
@@ -1536,6 +1536,11 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
}
+ if (parsedline->auth_method == uaSASL)
+ {
+ MANDATORY_AUTH_ARG(parsedline->sasl_protocol, "protocol", "sasl");
+ }
+
/*
* Enforce any parameters implied by other settings.
*/
@@ -1821,6 +1826,21 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
hbaline->radiusidentifier = pstrdup(val);
}
+ else if (strcmp(name, "protocol") == 0)
+ {
+ if (hbaline->auth_method != uaSASL)
+ INVALID_AUTH_OPTION("protocol", gettext_noop("sasl"));
+ if (strcmp(val, "scram_sha_256") != 0)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("invalid protocol name for SASL: \"%s\"", val),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ *err_msg = psprintf("invalid protocl name for SASL: \"%s\"", val);
+ }
+ hbaline->sasl_protocol = pstrdup(val);
+ }
else
{
ereport(elevel,
@@ -2077,6 +2097,13 @@ gethba_options(HbaLine *hba)
options[noptions++] =
CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
+ if (hba->auth_method == uaSASL)
+ {
+ if (hba->sasl_protocol)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("protocol=%s", hba->sasl_protocol));
+ }
+
if (hba->auth_method == uaLDAP)
{
if (hba->ldapserver)
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 73f7973ea2..3b04d2367f 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -42,9 +42,9 @@
# or "samenet" to match any address in any subnet that the server is
# directly connected to.
#
-# METHOD can be "trust", "reject", "md5", "password", "scram", "gss",
+# METHOD can be "trust", "reject", "md5", "password", "sasl", "gss",
# "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
-# "password" sends passwords in clear text; "md5" or "scram" are preferred
+# "password" sends passwords in clear text; "md5" or "sasl" are preferred
# since they send encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 4968fc783e..52fb1372ca 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -75,7 +75,7 @@
extern const char *select_default_timezone(const char *share_path);
static const char *const auth_methods_host[] = {
- "trust", "reject", "md5", "password", "scram", "ident", "radius",
+ "trust", "reject", "md5", "password", "sasl", "ident", "radius",
#ifdef ENABLE_GSS
"gss",
#endif
@@ -97,7 +97,7 @@ static const char *const auth_methods_host[] = {
NULL
};
static const char *const auth_methods_local[] = {
- "trust", "reject", "md5", "scram", "password", "peer", "radius",
+ "trust", "reject", "md5", "sasl", "password", "peer", "radius",
#ifdef USE_PAM
"pam", "pam ",
#endif
@@ -1128,8 +1128,8 @@ setup_config(void)
"#update_process_title = off");
#endif
- if (strcmp(authmethodlocal, "scram") == 0 ||
- strcmp(authmethodhost, "scram") == 0)
+ if (strcmp(authmethodlocal, "sasl") == 0 ||
+ strcmp(authmethodhost, "sasl") == 0)
{
conflines = replace_token(conflines,
"#password_encryption = md5",
@@ -2316,16 +2316,16 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost)
{
if ((strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0) &&
+ strcmp(authmethodlocal, "sasl") == 0) &&
(strcmp(authmethodhost, "md5") == 0 ||
strcmp(authmethodhost, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0) &&
+ strcmp(authmethodlocal, "sasl") == 0) &&
!(pwprompt || pwfilename))
{
fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
(strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0)
+ strcmp(authmethodlocal, "sasl") == 0)
? authmethodlocal
: authmethodhost);
exit(1);
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 8f55edb16a..51968c98b8 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -93,6 +93,7 @@ typedef struct HbaLine
char *radiussecret;
char *radiusidentifier;
int radiusport;
+ char *sasl_protocol;
} HbaLine;
typedef struct IdentLine
diff --git a/src/test/recovery/t/010_authentication.pl b/src/test/recovery/t/010_authentication.pl
index 16be7f5cc8..c68a1093f6 100644
--- a/src/test/recovery/t/010_authentication.pl
+++ b/src/test/recovery/t/010_authentication.pl
@@ -16,11 +16,17 @@ use Test::More tests => 12;
# and then execute a reload to refresh it.
sub reset_pg_hba
{
- my $node = shift;
- my $hba_method = shift;
+ my ($node, $hba_method, $options) = @_;
unlink($node->data_dir . '/pg_hba.conf');
- $node->append_conf('pg_hba.conf', "local all all $hba_method");
+ if (defined($options))
+ {
+ $node->append_conf('pg_hba.conf', "local all all $hba_method $options");
+ }
+ else
+ {
+ $node->append_conf('pg_hba.conf', "local all all $hba_method");
+ }
$node->reload;
}
@@ -71,7 +77,7 @@ SKIP:
# For "scram" method, user "plain_role" and "scram_role" should be able to
# connect.
- reset_pg_hba($node, 'scram');
+ reset_pg_hba($node, 'sasl', 'protocol=scram_sha_256');
test_role($node, 'scram_role', 'scram', 0);
test_role($node, 'md5_role', 'scram', 2);
test_role($node, 'plain_role', 'scram', 0);
--
2.12.0
I'm studying the normalization of Unicode so I apologize possible
stupidity in advance.
At Thu, 2 Mar 2017 15:50:34 +0900, Michael Paquier <michael.paquier@gmail.com> wrote in <CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g@mail.gmail.com>
On Tue, Feb 21, 2017 at 9:53 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Mon, Feb 20, 2017 at 9:41 PM, Aleksander Alekseev
<a.alekseev@postgrespro.ru> wrote:Speaking about flaws, it looks like there is a memory leak in
array_to_utf procedure - result is allocated twice.Pushed a fix for this one on my branch.
And a few more things I've noticed after a closer look:
* build_client_first_message does not free `state->client_nonce` if
second malloc (for `buf`) fails
* same for `state->client_first_message_bare`
* ... and most other procedures declared in fe-auth-scram.c file
(see malloc and strdup calls)You are visibly missing pg_fe_scram_free().
* scram_Normalize doesn't check malloc return value
Yes, I am aware of this one. This makes the interface utterly ugly
though because an error log message needs to be handled across many
API layers. We could just assume anything returning NULL is equivalent
to an OOM and nothing else though.Attached is a new patch set. I have combined SASLprep with the rest
and fixed some conflicts. At the same time when going through NFKC
this morning I have noticed that the implementation was doing the
canonical decomposition and reordered the characters using the
combining classes, but the string recomposition was still missing.
This is addressed in this patch set, and well as on my dev tree:
https://github.com/michaelpq/postgres/tree/scram
I looked into this and have some comments. Sorry for the random
order.
====
Composition version should be written some where.
====
Perhaps one of the most important things is that the code exactly
reflects the TR. pg_utf8_check_string returns true for ASCII
strings but the TR says that
| Text containing only ASCII characters (U+0000 to U+007F) is left
| unaffected by all of the normalization forms. This is
| particularly important for programming languages
And running SASLprepare for apparent ASCII string (which is the
most case) is a waste of CPU cycles.
====
From the point of view of reflectivity(please someone teach me an
appropreate wording for this..), basically the code had better to
be a copy of the reference code as long as no performance
degradation occurs. Hangul part of get_decomposed_size(and
decompose_code, recompose_code) uses different naming from the
TR. hindex should be sindex and t should be tindex. Magic numbers
should have names in the TR.
* A bit later, I noticed that these are copies of charlint. If so
I want a description about that.)
====
The following comment is equivalent to "reordering in canonical
order". But the definition of "decomposition" includes this
step. (I'm not sure if it needs rewriting, since I acutually
could understand that.)
/*
* Now that the decomposition is done, apply the combining class
* for each multibyte character.
*/
====
utf_sasl_prepare does canonical ordering in a bit different way
than the TR. Totally it should make a sequence of characters
starts with combining class = 0 and in the order of combining
class. The code does stable bubble sort within each combining
character and it seems to work as the same way. (In short, no
probelm found here.)
====
* make the allocation of the recomposed string based on that assumption.
*/
recomp_chars = (pg_wchar *) malloc(decomp_size * sizeof(int));
lastClass = -1; /* this eliminates a special check */
utf_sasl_prepare uses variable names with two naming
conventions. Is there any reason for the two?
====
starterCh = recomp_chars[0] = decomp_chars[0];
starterCh reads as "starter channel" why not "starter_char"?
====
Other than the magic numbers, I don't think that the following is
not a good expression.
else if (start >= 0xAC00 && start < 0xD7A4 &&
!((start - 0xAC00) % 28) &&
code >= 0x11A8 && code < 0x11C3)
"!((start - 0xAC00) % 28)" is a similar of !strcmp(a, b) and it
is confusing. It would be better to be "((start - 0xAC00) % 28) == 0".
The last sub-condition "code >= 0x11A8 && code < 0x11C3"
corresnponds to "(0 <= TIndex && TIndex <= TCount)". TIndex here
is (code - 0x11a7) and TCount = 28 so this two are not identical.
Totally the condition should be like the following.
else if (start >= 0xAC00 && start < 0xD7A4 &&
((start - 0xAC00) % 28) == 0 &&
code >= 0x11A7 && code <= 0x11C3)
The more preferable form is
else if (start >= SBASE && start < (SBASE + SCOUNT) &&
((start - SBASE) % TCOUNT) == 0 &&
code >= TBASE && code <= (TBASE + TCOUNT))
"code <= (TBASE + TCOUNT)" somewhat smells. Then I found the
original code for the current implementation in charlint and it
seems correct to me. Some description about the difference
between them is needed.
====
In use_sasl_prepare, the recompose part i sthe copy of charlint
but it seems a bit inefficient. It calls recompose_code
unconditionally but it is required only for the case of
"lastClass < chClass".
Something like this. (This still calls recompose_code for the
case that ch is the same position with starterChar so there still
be room for more improvement.)
if (lastClass < chClass &&
recompose_code(starterCh, ch, &composite))
recomp_chars[starterPos] = composite;
starterCh = composite;
}
else if (chClass == 0)
....
====
If I read the TR correctly, "6 Composition Exclusion Table" says
that there some characters not to be composed. But I don't find
the corresponding code. (or comments)
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Mar 2, 2017 at 9:13 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
I'm studying the normalization of Unicode so I apologize possible
stupidity in advance.I looked into this and have some comments. Sorry for the random
order.
Thanks, this needs a lot of background and I am glad that somebody is
taking the time to look at what I am doing here.
====
Composition version should be written some where.
Sure.
====
Perhaps one of the most important things is that the code exactly
reflects the TR. pg_utf8_check_string returns true for ASCII
strings but the TR says that| Text containing only ASCII characters (U+0000 to U+007F) is left
| unaffected by all of the normalization forms. This is
| particularly important for programming languagesAnd running SASLprepare for apparent ASCII string (which is the
most case) is a waste of CPU cycles.
Yeah, that's true. We could just for example check in
pg_utf8_check_string() if the length gathered matches strlen(source)
as only ASCII are 1-byte long.
====
From the point of view of reflectivity (please someone teach me an
appropreate wording for this..), basically the code had better to
be a copy of the reference code as long as no performance
degradation occurs. Hangul part of get_decomposed_size(and
decompose_code, recompose_code) uses different naming from the
TR. hindex should be sindex and t should be tindex. Magic numbers
should have names in the TR.* A bit later, I noticed that these are copies of charlint. If so
I want a description about that.)
Yeah, their stuff works quite nicely.
====
The following comment is equivalent to "reordering in canonical
order". But the definition of "decomposition" includes this
step. (I'm not sure if it needs rewriting, since I acutually
could understand that.)/*
* Now that the decomposition is done, apply the combining class
* for each multibyte character.
*/
I have reworked a bit this one:
/*
- * Now that the decomposition is done, apply the combining class
- * for each multibyte character.
+ * Now end the decomposition by applying the combining class for
+ * each multibyte character.
*/
====
* make the allocation of the recomposed string based on that assumption.
*/
recomp_chars = (pg_wchar *) malloc(decomp_size * sizeof(int));
lastClass = -1; /* this eliminates a special check */utf_sasl_prepare uses variable names with two naming
conventions. Is there any reason for the two?
OK, did some adjustments here.
====
starterCh = recomp_chars[0] = decomp_chars[0];
starterCh reads as "starter channel" why not "starter_char"?
Starter character of the current set, which is a character with a
combining class of 0.
====
else if (start >= SBASE && start < (SBASE + SCOUNT) &&
((start - SBASE) % TCOUNT) == 0 &&
code >= TBASE && code <= (TBASE + TCOUNT))"code <= (TBASE + TCOUNT)" somewhat smells. Then I found the
original code for the current implementation in charlint and it
seems correct to me. Some description about the difference
between them is needed.
Right. I have updated all those things to use constants instead of
hardcoded values.
====
In use_sasl_prepare, the recompose part is the copy of charlint
but it seems a bit inefficient. It calls recompose_code
unconditionally but it is required only for the case of
"lastClass < chClass".Something like this. (This still calls recompose_code for the
case that ch is the same position with starterChar so there still
be room for more improvement.)
Agreed.
====
If I read the TR correctly, "6 Composition Exclusion Table" says
that there some characters not to be composed. But I don't find
the corresponding code. (or comments)
Ah, right! There are 100 characters that enter in this category, and
all of them have a combining class of 0, so it is as simple as
removing them from the tables generated.
I am attaching 0009 and 0010 that address those problems (pushed on
github as well) that can be applied on top of the latest set.
--
Michael
Attachments:
0009-Set-of-fixes-for-SASLprep.patchapplication/octet-stream; name=0009-Set-of-fixes-for-SASLprep.patchDownload
From 7b3bc97b7dfae464321c8f4682f5eaf571214045 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 3 Mar 2017 14:25:09 +0900
Subject: [PATCH 09/10] Set of fixes for SASLprep
Some variable renames, as well as calculation of Hangul characters are
adjusted.
Per review from Kyotaro Horiguchi.
---
src/common/scram-common.c | 8 +++-
src/common/utf_norm.c | 106 +++++++++++++++++++++++++---------------------
2 files changed, 65 insertions(+), 49 deletions(-)
diff --git a/src/common/scram-common.c b/src/common/scram-common.c
index 041cf58f20..b262356325 100644
--- a/src/common/scram-common.c
+++ b/src/common/scram-common.c
@@ -121,7 +121,9 @@ pg_utf_mblen(const unsigned char *s)
* Check validity of the given null-terminated string for UTF-8.
*
* This routine uses pg_utf_mblen() and pg_utf8_islegal() to check each
- * character of the string.
+ * character of the string. Strings made only of ASCII characters do not
+ * need to go through SASLprep, so let caller know as well in this case
+ * that the string is eligible in this case.
*/
static bool
pg_utf8_check_string(const unsigned char *source)
@@ -139,6 +141,10 @@ pg_utf8_check_string(const unsigned char *source)
p += l;
}
+ /* ASCII-only strings have no need to go through SASLprep */
+ if (l == strlen((const char*) source))
+ return false;
+
return true;
}
diff --git a/src/common/utf_norm.c b/src/common/utf_norm.c
index c953b66e5f..2e7d6264fd 100644
--- a/src/common/utf_norm.c
+++ b/src/common/utf_norm.c
@@ -4,7 +4,8 @@
* Unicode strings (NFKC, NFKD, NFC and NFD).
*
* This contains the common low-level routines to perform normalizations
- * per documentation here: http://www.unicode.org/reports/tr15/.
+ * per documentation here: http://www.unicode.org/reports/tr15/, using the
+ * composition version 3.0.
*
* Portions Copyright (c) 2017, PostgreSQL Global Development Group
*
@@ -23,6 +24,17 @@
#include "common/utf_norm_table.h"
#include "mb/pg_wchar.h"
+/* Constants for calculations wih Hangul characters */
+#define SBASE 0xAC00
+#define LBASE 0x1100
+#define VBASE 0x1161
+#define TBASE 0x11A7
+#define LCOUNT 19
+#define VCOUNT 21
+#define TCOUNT 28
+#define NCOUNT VCOUNT * TCOUNT
+#define SCOUNT LCOUNT * NCOUNT
+
/*
* utf_to_array
*
@@ -298,14 +310,14 @@ get_decomposed_size(pg_wchar code)
* See http://unicode.org/reports/tr15/tr15-18.html, annex 10 for details
* on the matter.
*/
- if (code >= 0xAC00 && code < 0xD7A4)
+ if (code >= SBASE && code < SBASE + SCOUNT)
{
- uint32 t, hindex;
+ uint32 tindex, sindex;
- hindex = code - 0xAC00;
- t = hindex % 28;
+ sindex = code - SBASE;
+ tindex = sindex % TCOUNT;
- if (t != 0)
+ if (tindex != 0)
return 3;
return 2;
}
@@ -344,21 +356,21 @@ static bool
recompose_code(uint32 start, uint32 code, uint32 *result)
{
/* No need to care about ascii characters */
- if (start <= 0xef || code <= 0xef)
+ if (start <= 0x7f || code <= 0x7f)
return false;
/* Hangul characters go here */
- if (start >= 0x1100 && start < 0x1113 &&
- code >= 0x1161 && code < 0x1176)
+ if (start >= LBASE && start < LBASE + LCOUNT &&
+ code >= VBASE && code < VBASE + VCOUNT)
{
- *result = ((start - 0x1100) * 21 + code - 0x1161) * 28 + 0xAC00;
+ *result = ((start - LBASE) * VCOUNT + code - VBASE) * TCOUNT + SBASE;
return true;
}
- else if (start >= 0xAC00 && start < 0xD7A4 &&
- !((start - 0xAC00) % 28) &&
- code >= 0x11A8 && code < 0x11C3)
+ else if (start >= SBASE && start < (SBASE + SCOUNT) &&
+ ((start - SBASE) % TCOUNT) == 0 &&
+ code >= TBASE && code < (TBASE + TCOUNT))
{
- *result = start + code - 0x11A7;
+ *result = start + code - TBASE;
return true;
}
else
@@ -406,24 +418,24 @@ decompose_code(pg_wchar code, pg_wchar **result, int *current)
* See http://unicode.org/reports/tr15/tr15-18.html, annex 10 for details
* on the matter.
*/
- if (code >= 0xAC00 && code < 0xD7A4)
+ if (code >= SBASE && code < SBASE + SCOUNT)
{
- uint32 l, v, t, hindex;
+ uint32 l, v, tindex, sindex;
pg_wchar *res = *result;
- hindex = code - 0xAC00;
- l = 0x1100 + hindex / (21 * 28);
- v = 0x1161 + (hindex % (21 * 28)) / 28;
- t = hindex % 28;
+ sindex = code - SBASE;
+ l = LBASE + sindex / (VCOUNT * TCOUNT);
+ v = VBASE + (sindex % (VCOUNT * TCOUNT)) / TCOUNT;
+ tindex = sindex % TCOUNT;
res[*current] = l;
(*current)++;
res[*current] = v;
(*current)++;
- if (t != 0)
+ if (tindex != 0)
{
- res[*current] = 0x11A7 + t;
+ res[*current] = TBASE + tindex;
(*current)++;
}
@@ -475,11 +487,10 @@ utf_sasl_prepare(const char *input)
int count;
char *result;
/* variables for recomposition */
- int lastClass;
- int starterPos;
- int sourceLength;
- int targetPos;
- uint32 starterCh;
+ int last_class;
+ int starter_pos;
+ int target_pos;
+ uint32 starter_ch;
/* Convert input string into a manipulable array of character integers */
input_chars = utf_to_array((char *) input, &input_size);
@@ -527,8 +538,8 @@ utf_sasl_prepare(const char *input)
Assert(decomp_size == current_size);
/*
- * Now that the decomposition is done, apply the combining class
- * for each multibyte character.
+ * Now end the decomposition by applying the combining class for
+ * each multibyte character.
*/
for (count = 1; count < decomp_size; count++)
{
@@ -577,40 +588,39 @@ utf_sasl_prepare(const char *input)
* make the allocation of the recomposed string based on that assumption.
*/
recomp_chars = (pg_wchar *) malloc(decomp_size * sizeof(int));
- lastClass = -1; /* this eliminates a special check */
- starterPos = 0;
- sourceLength = decomp_size;
- targetPos = 1;
- starterCh = recomp_chars[0] = decomp_chars[0];
+ last_class = -1; /* this eliminates a special check */
+ starter_pos = 0;
+ target_pos = 1;
+ starter_ch = recomp_chars[0] = decomp_chars[0];
for (count = 1; count < decomp_size; count++)
{
pg_wchar ch = decomp_chars[count];
- pg_utf_decomposition *chEntry = get_code_entry(ch);
- int chClass = chEntry == NULL ? 0 : chEntry->class;
+ pg_utf_decomposition *ch_entry = get_code_entry(ch);
+ int ch_class = ch_entry == NULL ? 0 : ch_entry->class;
pg_wchar composite;
- bool found_match = recompose_code(starterCh, ch, &composite);
+ bool found_match = recompose_code(starter_ch, ch, &composite);
- if (found_match && lastClass < chClass)
+ if (found_match && last_class < ch_class)
{
- recomp_chars[starterPos] = composite;
- starterCh = composite;
+ recomp_chars[starter_pos] = composite;
+ starter_ch = composite;
}
- else if (chClass == 0)
+ else if (ch_class == 0)
{
- starterPos = targetPos;
- starterCh = ch;
- lastClass = -1;
- recomp_chars[targetPos++] = ch;
+ starter_pos = target_pos;
+ starter_ch = ch;
+ last_class = -1;
+ recomp_chars[target_pos++] = ch;
}
else
{
- lastClass = chClass;
- recomp_chars[targetPos++] = ch;
+ last_class = ch_class;
+ recomp_chars[target_pos++] = ch;
}
}
- recomp_size = targetPos;
+ recomp_size = target_pos;
/*
* Convert the decomposition back to a string, which is the final
--
2.12.0
0010-Consider-characters-excluded-from-composition-in-con.patchapplication/octet-stream; name=0010-Consider-characters-excluded-from-composition-in-con.patchDownload
From ee1ac8f16d0b881336e886b54566851c78b070cc Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 3 Mar 2017 14:40:23 +0900
Subject: [PATCH 10/10] Consider characters excluded from composition in
conversion tables
Noted by Kyotaro Horiguchi.
---
src/common/utf_norm_generate.pl | 111 ++++++++++++++++++++++++
src/include/common/utf_norm_table.h | 164 +-----------------------------------
2 files changed, 113 insertions(+), 162 deletions(-)
diff --git a/src/common/utf_norm_generate.pl b/src/common/utf_norm_generate.pl
index 73c7925572..e03316e074 100644
--- a/src/common/utf_norm_generate.pl
+++ b/src/common/utf_norm_generate.pl
@@ -43,6 +43,93 @@ my $input_file = $ARGV[0];
my $output_file = $ARGV[1];
my $output_base = basename($output_file);
+# Script-specific and post composition that need to be excluded from the tables
+# generated per http://www.unicode.org/reports/tr15/.
+my @no_recomp_codes = (
+ '0958', # DEVANAGARI LETTER QA
+ '0959', # DEVANAGARI LETTER KHHA
+ '095A', # DEVANAGARI LETTER GHHA
+ '095B', # DEVANAGARI LETTER ZA
+ '095C', # DEVANAGARI LETTER DDDHA
+ '095D', # DEVANAGARI LETTER RHA
+ '095E', # DEVANAGARI LETTER FA
+ '095F', # DEVANAGARI LETTER YYA
+ '09DC', # BENGALI LETTER RRA
+ '09DD', # BENGALI LETTER RHA
+ '09DF', # BENGALI LETTER YYA
+ '0A33', # GURMUKHI LETTER LLA
+ '0A36', # GURMUKHI LETTER SHA
+ '0A59', # GURMUKHI LETTER KHHA
+ '0A5A', # GURMUKHI LETTER GHHA
+ '0A5B', # GURMUKHI LETTER ZA
+ '0A5E', # GURMUKHI LETTER FA
+ '0B5C', # ORIYA LETTER RRA
+ '0B5D', # ORIYA LETTER RHA
+ '0F43', # TIBETAN LETTER GHA
+ '0F4D', # TIBETAN LETTER DDHA
+ '0F52', # TIBETAN LETTER DHA
+ '0F57', # TIBETAN LETTER BHA
+ '0F5C', # TIBETAN LETTER DZHA
+ '0F69', # TIBETAN LETTER KSSA
+ '0F76', # TIBETAN VOWEL SIGN VOCALIC R
+ '0F78', # TIBETAN VOWEL SIGN VOCALIC L
+ '0F93', # TIBETAN SUBJOINED LETTER GHA
+ '0F9D', # TIBETAN SUBJOINED LETTER DDHA
+ '0FA2', # TIBETAN SUBJOINED LETTER DHA
+ '0FA7', # TIBETAN SUBJOINED LETTER BHA
+ '0FAC', # TIBETAN SUBJOINED LETTER DZHA
+ '0FB9', # TIBETAN SUBJOINED LETTER KSSA
+ # 'FB1D' # HEBREW LETTER YOD WITH HIRIQ: see below for $OPTYWH
+ 'FB1F', # HEBREW LIGATURE YIDDISH YOD YOD PATAH
+ 'FB2A', # HEBREW LETTER SHIN WITH SHIN DOT
+ 'FB2B', # HEBREW LETTER SHIN WITH SIN DOT
+ 'FB2C', # HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT
+ 'FB2D', # HEBREW LETTER SHIN WITH DAGESH AND SIN DOT
+ 'FB2E', # HEBREW LETTER ALEF WITH PATAH
+ 'FB2F', # HEBREW LETTER ALEF WITH QAMATS
+ 'FB30', # HEBREW LETTER ALEF WITH MAPIQ
+ 'FB31', # HEBREW LETTER BET WITH DAGESH
+ 'FB32', # HEBREW LETTER GIMEL WITH DAGESH
+ 'FB33', # HEBREW LETTER DALET WITH DAGESH
+ 'FB34', # HEBREW LETTER HE WITH MAPIQ
+ 'FB35', # HEBREW LETTER VAV WITH DAGESH
+ 'FB36', # HEBREW LETTER ZAYIN WITH DAGESH
+ 'FB38', # HEBREW LETTER TET WITH DAGESH
+ 'FB39', # HEBREW LETTER YOD WITH DAGESH
+ 'FB3A', # HEBREW LETTER FINAL KAF WITH DAGESH
+ 'FB3B', # HEBREW LETTER KAF WITH DAGESH
+ 'FB3C', # HEBREW LETTER LAMED WITH DAGESH
+ 'FB3E', # HEBREW LETTER MEM WITH DAGESH
+ 'FB40', # HEBREW LETTER NUN WITH DAGESH
+ 'FB41', # HEBREW LETTER SAMEKH WITH DAGESH
+ 'FB43', # HEBREW LETTER FINAL PE WITH DAGESH
+ 'FB44', # HEBREW LETTER PE WITH DAGESH
+ 'FB46', # HEBREW LETTER TSADI WITH DAGESH
+ 'FB47', # HEBREW LETTER QOF WITH DAGESH
+ 'FB48', # HEBREW LETTER RESH WITH DAGESH
+ 'FB49', # HEBREW LETTER SHIN WITH DAGESH
+ 'FB4A', # HEBREW LETTER TAV WITH DAGESH
+ 'FB4B', # HEBREW LETTER VAV WITH HOLAM
+ 'FB4C', # HEBREW LETTER BET WITH RAFE
+ 'FB4D', # HEBREW LETTER KAF WITH RAFE
+ 'FB4E', # HEBREW LETTER PE WITH RAFE
+ ## post composition exclusion
+ '2ADC', # FORKING
+ '1D15E', # MUSICAL SYMBOL HALF NOTE
+ '1D15F', # MUSICAL SYMBOL QUARTER NOTE
+ '1D160', # MUSICAL SYMBOL EIGHTH NOTE
+ '1D161', # MUSICAL SYMBOL SIXTEENTH NOTE
+ '1D162', # MUSICAL SYMBOL THIRTY-SECOND NOTE
+ '1D163', # MUSICAL SYMBOL SIXTY-FOURTH NOTE
+ '1D164', # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+ '1D1BB', # MUSICAL SYMBOL MINIMA
+ '1D1BC', # MUSICAL SYMBOL MINIMA BLACK
+ '1D1BD', # MUSICAL SYMBOL SEMIMINIMA WHITE
+ '1D1BE', # MUSICAL SYMBOL SEMIMINIMA BLACK
+ '1D1BF', # MUSICAL SYMBOL FUSA WHITE
+ '1D1C0' # MUSICAL SYMBOL FUSA BLACK
+ );
+
# Count number of lines in input file to get size of table.
my $input_lines = 0;
open(my $FH, $input_file) or die "Could not open input file $input_file: $!.";
@@ -54,6 +141,18 @@ while (my $line = <$FH>)
# Skip codes longer than 4 bytes, or 8 characters.
next if length($code) > 8;
+ # Skip codes that cannot be composed
+ my $found_no_recomp = 0;
+ foreach my $lcode (@no_recomp_codes)
+ {
+ if ($lcode eq $elts[0])
+ {
+ $found_no_recomp = 1;
+ last;
+ }
+ }
+ next if $found_no_recomp;
+
# Skip characters with no decompositions and a class of 0.
next if $elts[3] eq '0' && $elts[5] eq '';
@@ -116,6 +215,18 @@ while ( my $line = <$INPUT> )
# Skip codes longer than 4 bytes, or 8 characters.
next if length($code) > 8;
+ # Skip codes that cannot be composed
+ my $found_no_recomp = 0;
+ foreach my $lcode (@no_recomp_codes)
+ {
+ if ($lcode eq $elts[0])
+ {
+ $found_no_recomp = 1;
+ last;
+ }
+ }
+ next if $found_no_recomp;
+
# Skip characters with no decompositions and a class of 0.
# to reduce the table size.
next if $elts[3] eq '0' && $elts[5] eq '';
diff --git a/src/include/common/utf_norm_table.h b/src/include/common/utf_norm_table.h
index e84f9fd693..9fa3b7ca99 100644
--- a/src/include/common/utf_norm_table.h
+++ b/src/include/common/utf_norm_table.h
@@ -24,7 +24,7 @@ typedef struct
} pg_utf_decomposition;
/* conversion table */
-static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
+static const pg_utf_decomposition UtfDecompMain[ 6452 ] =
{
{0xc2a0, 0x00, 1},
{0xc2a8, 0x00, 2},
@@ -766,29 +766,12 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe0a592, 0xdc, 0},
{0xe0a593, 0xe6, 0},
{0xe0a594, 0xe6, 0},
- {0xe0a598, 0x00, 2},
- {0xe0a599, 0x00, 2},
- {0xe0a59a, 0x00, 2},
- {0xe0a59b, 0x00, 2},
- {0xe0a59c, 0x00, 2},
- {0xe0a59d, 0x00, 2},
- {0xe0a59e, 0x00, 2},
- {0xe0a59f, 0x00, 2},
{0xe0a6bc, 0x07, 0},
{0xe0a78b, 0x00, 2},
{0xe0a78c, 0x00, 2},
{0xe0a78d, 0x09, 0},
- {0xe0a79c, 0x00, 2},
- {0xe0a79d, 0x00, 2},
- {0xe0a79f, 0x00, 2},
- {0xe0a8b3, 0x00, 2},
- {0xe0a8b6, 0x00, 2},
{0xe0a8bc, 0x07, 0},
{0xe0a98d, 0x09, 0},
- {0xe0a999, 0x00, 2},
- {0xe0a99a, 0x00, 2},
- {0xe0a99b, 0x00, 2},
- {0xe0a99e, 0x00, 2},
{0xe0aabc, 0x07, 0},
{0xe0ab8d, 0x09, 0},
{0xe0acbc, 0x07, 0},
@@ -796,8 +779,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe0ad8b, 0x00, 2},
{0xe0ad8c, 0x00, 2},
{0xe0ad8d, 0x09, 0},
- {0xe0ad9c, 0x00, 2},
- {0xe0ad9d, 0x00, 2},
{0xe0ae94, 0x00, 2},
{0xe0af8a, 0x00, 2},
{0xe0af8b, 0x00, 2},
@@ -846,20 +827,12 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe0bcb5, 0xdc, 0},
{0xe0bcb7, 0xdc, 0},
{0xe0bcb9, 0xd8, 0},
- {0xe0bd83, 0x00, 2},
- {0xe0bd8d, 0x00, 2},
- {0xe0bd92, 0x00, 2},
- {0xe0bd97, 0x00, 2},
- {0xe0bd9c, 0x00, 2},
- {0xe0bda9, 0x00, 2},
{0xe0bdb1, 0x81, 0},
{0xe0bdb2, 0x82, 0},
{0xe0bdb3, 0x00, 2},
{0xe0bdb4, 0x84, 0},
{0xe0bdb5, 0x00, 2},
- {0xe0bdb6, 0x00, 2},
{0xe0bdb7, 0x00, 2},
- {0xe0bdb8, 0x00, 2},
{0xe0bdb9, 0x00, 2},
{0xe0bdba, 0x82, 0},
{0xe0bdbb, 0x82, 0},
@@ -872,12 +845,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe0be84, 0x09, 0},
{0xe0be86, 0xe6, 0},
{0xe0be87, 0xe6, 0},
- {0xe0be93, 0x00, 2},
- {0xe0be9d, 0x00, 2},
- {0xe0bea2, 0x00, 2},
- {0xe0bea7, 0x00, 2},
- {0xe0beac, 0x00, 2},
- {0xe0beb9, 0x00, 2},
{0xe0bf86, 0xdc, 0},
{0xe180a6, 0x00, 2},
{0xe180b7, 0x07, 0},
@@ -2008,7 +1975,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe2a9b4, 0x00, 3},
{0xe2a9b5, 0x00, 2},
{0xe2a9b6, 0x00, 3},
- {0xe2ab9c, 0x00, 2},
{0xe2b1bc, 0x00, 1},
{0xe2b1bd, 0x00, 1},
{0xe2b3af, 0xe6, 0},
@@ -3483,7 +3449,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xefac97, 0x00, 2},
{0xefac9d, 0x00, 2},
{0xefac9e, 0x1a, 0},
- {0xefac9f, 0x00, 2},
{0xefaca0, 0x00, 1},
{0xefaca1, 0x00, 1},
{0xefaca2, 0x00, 1},
@@ -3494,38 +3459,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xefaca7, 0x00, 1},
{0xefaca8, 0x00, 1},
{0xefaca9, 0x00, 1},
- {0xefacaa, 0x00, 2},
- {0xefacab, 0x00, 2},
- {0xefacac, 0x00, 2},
- {0xefacad, 0x00, 2},
- {0xefacae, 0x00, 2},
- {0xefacaf, 0x00, 2},
- {0xefacb0, 0x00, 2},
- {0xefacb1, 0x00, 2},
- {0xefacb2, 0x00, 2},
- {0xefacb3, 0x00, 2},
- {0xefacb4, 0x00, 2},
- {0xefacb5, 0x00, 2},
- {0xefacb6, 0x00, 2},
- {0xefacb8, 0x00, 2},
- {0xefacb9, 0x00, 2},
- {0xefacba, 0x00, 2},
- {0xefacbb, 0x00, 2},
- {0xefacbc, 0x00, 2},
- {0xefacbe, 0x00, 2},
- {0xefad80, 0x00, 2},
- {0xefad81, 0x00, 2},
- {0xefad83, 0x00, 2},
- {0xefad84, 0x00, 2},
- {0xefad86, 0x00, 2},
- {0xefad87, 0x00, 2},
- {0xefad88, 0x00, 2},
- {0xefad89, 0x00, 2},
- {0xefad8a, 0x00, 2},
- {0xefad8b, 0x00, 2},
- {0xefad8c, 0x00, 2},
- {0xefad8d, 0x00, 2},
- {0xefad8e, 0x00, 2},
{0xefad8f, 0x00, 2},
{0xefad90, 0x00, 1},
{0xefad91, 0x00, 1},
@@ -4646,13 +4579,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe19ab335, 0xe6, 0},
{0xe19ab336, 0xe6, 0},
{0xe1af8945, 0x01, 0},
- {0xe1b49545, 0x00, 2},
- {0xe1b49546, 0x00, 2},
- {0xe1b49630, 0x00, 2},
- {0xe1b49631, 0x00, 2},
- {0xe1b49632, 0x00, 2},
- {0xe1b49633, 0x00, 2},
- {0xe1b49634, 0x00, 2},
{0xe1b49635, 0xd8, 0},
{0xe1b49636, 0xd8, 0},
{0xe1b49637, 0x01, 0},
@@ -4683,12 +4609,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6532 ] =
{0xe1b49a42, 0xe6, 0},
{0xe1b49a43, 0xe6, 0},
{0xe1b49a44, 0xe6, 0},
- {0xe1b49b42, 0x00, 2},
- {0xe1b49b43, 0x00, 2},
- {0xe1b49b44, 0x00, 2},
- {0xe1b49b45, 0x00, 2},
- {0xe1b49b46, 0x00, 2},
- {0xe1b49c30, 0x00, 2},
{0xe1b4a432, 0xe6, 0},
{0xe1b4a433, 0xe6, 0},
{0xe1b4a434, 0xe6, 0},
@@ -10146,7 +10066,7 @@ typedef struct
uint32 decomp[2]; /* size of decomposition code list */
} pg_utf_decomposition_size_2;
-static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
+static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1591 ] =
{
{0xc2a8, {0x20, 0xcc88}},
{0xc2af, {0x20, 0xcc84}},
@@ -10521,30 +10441,11 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
{0xe0a4a9, {0xe0a4a8, 0xe0a4bc}},
{0xe0a4b1, {0xe0a4b0, 0xe0a4bc}},
{0xe0a4b4, {0xe0a4b3, 0xe0a4bc}},
- {0xe0a598, {0xe0a495, 0xe0a4bc}},
- {0xe0a599, {0xe0a496, 0xe0a4bc}},
- {0xe0a59a, {0xe0a497, 0xe0a4bc}},
- {0xe0a59b, {0xe0a49c, 0xe0a4bc}},
- {0xe0a59c, {0xe0a4a1, 0xe0a4bc}},
- {0xe0a59d, {0xe0a4a2, 0xe0a4bc}},
- {0xe0a59e, {0xe0a4ab, 0xe0a4bc}},
- {0xe0a59f, {0xe0a4af, 0xe0a4bc}},
{0xe0a78b, {0xe0a787, 0xe0a6be}},
{0xe0a78c, {0xe0a787, 0xe0a797}},
- {0xe0a79c, {0xe0a6a1, 0xe0a6bc}},
- {0xe0a79d, {0xe0a6a2, 0xe0a6bc}},
- {0xe0a79f, {0xe0a6af, 0xe0a6bc}},
- {0xe0a8b3, {0xe0a8b2, 0xe0a8bc}},
- {0xe0a8b6, {0xe0a8b8, 0xe0a8bc}},
- {0xe0a999, {0xe0a896, 0xe0a8bc}},
- {0xe0a99a, {0xe0a897, 0xe0a8bc}},
- {0xe0a99b, {0xe0a89c, 0xe0a8bc}},
- {0xe0a99e, {0xe0a8ab, 0xe0a8bc}},
{0xe0ad88, {0xe0ad87, 0xe0ad96}},
{0xe0ad8b, {0xe0ad87, 0xe0acbe}},
{0xe0ad8c, {0xe0ad87, 0xe0ad97}},
- {0xe0ad9c, {0xe0aca1, 0xe0acbc}},
- {0xe0ad9d, {0xe0aca2, 0xe0acbc}},
{0xe0ae94, {0xe0ae92, 0xe0af97}},
{0xe0af8a, {0xe0af86, 0xe0aebe}},
{0xe0af8b, {0xe0af87, 0xe0aebe}},
@@ -10566,25 +10467,11 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
{0xe0bab3, {0xe0bb8d, 0xe0bab2}},
{0xe0bb9c, {0xe0baab, 0xe0ba99}},
{0xe0bb9d, {0xe0baab, 0xe0baa1}},
- {0xe0bd83, {0xe0bd82, 0xe0beb7}},
- {0xe0bd8d, {0xe0bd8c, 0xe0beb7}},
- {0xe0bd92, {0xe0bd91, 0xe0beb7}},
- {0xe0bd97, {0xe0bd96, 0xe0beb7}},
- {0xe0bd9c, {0xe0bd9b, 0xe0beb7}},
- {0xe0bda9, {0xe0bd80, 0xe0beb5}},
{0xe0bdb3, {0xe0bdb1, 0xe0bdb2}},
{0xe0bdb5, {0xe0bdb1, 0xe0bdb4}},
- {0xe0bdb6, {0xe0beb2, 0xe0be80}},
{0xe0bdb7, {0xe0beb2, 0xe0be81}},
- {0xe0bdb8, {0xe0beb3, 0xe0be80}},
{0xe0bdb9, {0xe0beb3, 0xe0be81}},
{0xe0be81, {0xe0bdb1, 0xe0be80}},
- {0xe0be93, {0xe0be92, 0xe0beb7}},
- {0xe0be9d, {0xe0be9c, 0xe0beb7}},
- {0xe0bea2, {0xe0bea1, 0xe0beb7}},
- {0xe0bea7, {0xe0bea6, 0xe0beb7}},
- {0xe0beac, {0xe0beab, 0xe0beb7}},
- {0xe0beb9, {0xe0be90, 0xe0beb5}},
{0xe180a6, {0xe180a5, 0xe180ae}},
{0xe1ac86, {0xe1ac85, 0xe1acb5}},
{0xe1ac88, {0xe1ac87, 0xe1acb5}},
@@ -11149,7 +11036,6 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
{0xe2928f, {0x38, 0x2e}},
{0xe29290, {0x39, 0x2e}},
{0xe2a9b5, {0x3d, 0x3d}},
- {0xe2ab9c, {0xe2ab9d, 0xccb8}},
{0xe3818c, {0xe3818b, 0xe38299}},
{0xe3818e, {0xe3818d, 0xe38299}},
{0xe38190, {0xe3818f, 0xe38299}},
@@ -11388,39 +11274,6 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
{0xefac96, {0xd5be, 0xd5b6}},
{0xefac97, {0xd5b4, 0xd5ad}},
{0xefac9d, {0xd799, 0xd6b4}},
- {0xefac9f, {0xd7b2, 0xd6b7}},
- {0xefacaa, {0xd7a9, 0xd781}},
- {0xefacab, {0xd7a9, 0xd782}},
- {0xefacac, {0xefad89, 0xd781}},
- {0xefacad, {0xefad89, 0xd782}},
- {0xefacae, {0xd790, 0xd6b7}},
- {0xefacaf, {0xd790, 0xd6b8}},
- {0xefacb0, {0xd790, 0xd6bc}},
- {0xefacb1, {0xd791, 0xd6bc}},
- {0xefacb2, {0xd792, 0xd6bc}},
- {0xefacb3, {0xd793, 0xd6bc}},
- {0xefacb4, {0xd794, 0xd6bc}},
- {0xefacb5, {0xd795, 0xd6bc}},
- {0xefacb6, {0xd796, 0xd6bc}},
- {0xefacb8, {0xd798, 0xd6bc}},
- {0xefacb9, {0xd799, 0xd6bc}},
- {0xefacba, {0xd79a, 0xd6bc}},
- {0xefacbb, {0xd79b, 0xd6bc}},
- {0xefacbc, {0xd79c, 0xd6bc}},
- {0xefacbe, {0xd79e, 0xd6bc}},
- {0xefad80, {0xd7a0, 0xd6bc}},
- {0xefad81, {0xd7a1, 0xd6bc}},
- {0xefad83, {0xd7a3, 0xd6bc}},
- {0xefad84, {0xd7a4, 0xd6bc}},
- {0xefad86, {0xd7a6, 0xd6bc}},
- {0xefad87, {0xd7a7, 0xd6bc}},
- {0xefad88, {0xd7a8, 0xd6bc}},
- {0xefad89, {0xd7a9, 0xd6bc}},
- {0xefad8a, {0xd7aa, 0xd6bc}},
- {0xefad8b, {0xd795, 0xd6b9}},
- {0xefad8c, {0xd791, 0xd6bf}},
- {0xefad8d, {0xd79b, 0xd6bf}},
- {0xefad8e, {0xd7a4, 0xd6bf}},
{0xefad8f, {0xd790, 0xd79c}},
{0xefafaa, {0xd8a6, 0xd8a7}},
{0xefafab, {0xd8a6, 0xd8a7}},
@@ -11783,19 +11636,6 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1671 ] =
{0xe1858b45, {0xe1858b39, 0xe1858b44}},
{0xe1859b41, {0xe1859b38, 0xe1859a46}},
{0xe1859b42, {0xe1859b39, 0xe1859a46}},
- {0xe1b49545, {0xe1b49537, 0xe1b49635}},
- {0xe1b49546, {0xe1b49538, 0xe1b49635}},
- {0xe1b49630, {0xe1b49546, 0xe1b49645}},
- {0xe1b49631, {0xe1b49546, 0xe1b49646}},
- {0xe1b49632, {0xe1b49546, 0xe1b49730}},
- {0xe1b49633, {0xe1b49546, 0xe1b49731}},
- {0xe1b49634, {0xe1b49546, 0xe1b49732}},
- {0xe1b49b42, {0xe1b49b39, 0xe1b49635}},
- {0xe1b49b43, {0xe1b49b41, 0xe1b49635}},
- {0xe1b49b44, {0xe1b49b42, 0xe1b49645}},
- {0xe1b49b45, {0xe1b49b43, 0xe1b49645}},
- {0xe1b49b46, {0xe1b49b42, 0xe1b49646}},
- {0xe1b49c30, {0xe1b49b43, 0xe1b49646}},
{0xe1bc9030, {0x30, 0x2e}},
{0xe1bc9031, {0x30, 0x2c}},
{0xe1bc9032, {0x31, 0x2c}},
--
2.12.0
On Fri, Mar 3, 2017 at 2:43 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
I am attaching 0009 and 0010 that address those problems (pushed on
github as well) that can be applied on top of the latest set.
While doing more tests with my module able to do SASLprep, I have
noticed that calculations related to Hangul characters were incorrect:
/* Constants for calculations wih Hangul characters */
-#define SBASE 0xAC00
-#define LBASE 0x1100
-#define VBASE 0x1161
-#define TBASE 0x11A7
+#define SBASE 0xEAB080 /* U+AC00 */
+#define LBASE 0xE18480 /* U+1100 */
+#define VBASE 0xE185A1 /* U+1161 */
+#define TBASE 0xE186A7 /* U+11A7 */
Once the following is applied things get better:
-- Test for U+FB01, Latin Small Ligature Fi
=# select array_to_utf8(pg_sasl_prepare(utf8_to_array('fi')));
array_to_utf8
---------------
fi
(1 row)
-- Test for U+1E9B, Latin Small Letter Long S with Dot Above
-- This one was failing previously.
=# select array_to_utf8(pg_sasl_prepare(utf8_to_array('ẛ')));
array_to_utf8
---------------
ṡ
(1 row)
-- Test for U+2075, superscript 5
=# select array_to_utf8(pg_sasl_prepare(utf8_to_array('⁵')));
array_to_utf8
---------------
5
(1 row)
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Mar 6, 2017 at 11:50 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Fri, Mar 3, 2017 at 2:43 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:I am attaching 0009 and 0010 that address those problems (pushed on
github as well) that can be applied on top of the latest set.While doing more tests with my module able to do SASLprep, I have noticed that calculations related to Hangul characters were incorrect: /* Constants for calculations wih Hangul characters */ -#define SBASE 0xAC00 -#define LBASE 0x1100 -#define VBASE 0x1161 -#define TBASE 0x11A7 +#define SBASE 0xEAB080 /* U+AC00 */ +#define LBASE 0xE18480 /* U+1100 */ +#define VBASE 0xE185A1 /* U+1161 */ +#define TBASE 0xE186A7 /* U+11A7 */
Here is as well an extra patch with this set of fixes, to be applied
on top of the rest. Those are on my github as well, that's for the
archive's sake, and that's better than sending a full set of patches
again.
--
Michael
Attachments:
0011-Set-of-fixes-for-SASLprep.patchapplication/octet-stream; name=0011-Set-of-fixes-for-SASLprep.patchDownload
From c6db7527ad14138f8c4183d1d6261d07500f404b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 6 Mar 2017 11:52:36 +0900
Subject: [PATCH 11/11] Set of fixes for SASLprep
The following things are fixed here:
- Incorrect allocation.
- Code borders for Hangul calculations.
---
src/common/utf_norm.c | 14 +++++++-------
src/common/utf_norm_generate.pl | 2 +-
src/include/common/utf_norm_table.h | 6 ++----
3 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/src/common/utf_norm.c b/src/common/utf_norm.c
index 2e7d6264fd..d91028fe2a 100644
--- a/src/common/utf_norm.c
+++ b/src/common/utf_norm.c
@@ -25,10 +25,10 @@
#include "mb/pg_wchar.h"
/* Constants for calculations wih Hangul characters */
-#define SBASE 0xAC00
-#define LBASE 0x1100
-#define VBASE 0x1161
-#define TBASE 0x11A7
+#define SBASE 0xEAB080 /* U+AC00 */
+#define LBASE 0xE18480 /* U+1100 */
+#define VBASE 0xE185A1 /* U+1161 */
+#define TBASE 0xE186A7 /* U+11A7 */
#define LCOUNT 19
#define VCOUNT 21
#define TCOUNT 28
@@ -587,7 +587,7 @@ utf_sasl_prepare(const char *input)
* recomposed string cannot be longer than the decomposed one, so
* make the allocation of the recomposed string based on that assumption.
*/
- recomp_chars = (pg_wchar *) malloc(decomp_size * sizeof(int));
+ recomp_chars = (pg_wchar *) malloc(decomp_size * sizeof(pg_wchar));
last_class = -1; /* this eliminates a special check */
starter_pos = 0;
target_pos = 1;
@@ -599,9 +599,9 @@ utf_sasl_prepare(const char *input)
pg_utf_decomposition *ch_entry = get_code_entry(ch);
int ch_class = ch_entry == NULL ? 0 : ch_entry->class;
pg_wchar composite;
- bool found_match = recompose_code(starter_ch, ch, &composite);
- if (found_match && last_class < ch_class)
+ if (last_class < ch_class &&
+ recompose_code(starter_ch, ch, &composite))
{
recomp_chars[starter_pos] = composite;
starter_ch = composite;
diff --git a/src/common/utf_norm_generate.pl b/src/common/utf_norm_generate.pl
index e03316e074..b876cf3215 100644
--- a/src/common/utf_norm_generate.pl
+++ b/src/common/utf_norm_generate.pl
@@ -79,7 +79,7 @@ my @no_recomp_codes = (
'0FA7', # TIBETAN SUBJOINED LETTER BHA
'0FAC', # TIBETAN SUBJOINED LETTER DZHA
'0FB9', # TIBETAN SUBJOINED LETTER KSSA
- # 'FB1D' # HEBREW LETTER YOD WITH HIRIQ: see below for $OPTYWH
+ 'FB1D', # HEBREW LETTER YOD WITH HIRIQ:
'FB1F', # HEBREW LIGATURE YIDDISH YOD YOD PATAH
'FB2A', # HEBREW LETTER SHIN WITH SHIN DOT
'FB2B', # HEBREW LETTER SHIN WITH SIN DOT
diff --git a/src/include/common/utf_norm_table.h b/src/include/common/utf_norm_table.h
index 9fa3b7ca99..a5248c777e 100644
--- a/src/include/common/utf_norm_table.h
+++ b/src/include/common/utf_norm_table.h
@@ -24,7 +24,7 @@ typedef struct
} pg_utf_decomposition;
/* conversion table */
-static const pg_utf_decomposition UtfDecompMain[ 6452 ] =
+static const pg_utf_decomposition UtfDecompMain[ 6451 ] =
{
{0xc2a0, 0x00, 1},
{0xc2a8, 0x00, 2},
@@ -3447,7 +3447,6 @@ static const pg_utf_decomposition UtfDecompMain[ 6452 ] =
{0xefac95, 0x00, 2},
{0xefac96, 0x00, 2},
{0xefac97, 0x00, 2},
- {0xefac9d, 0x00, 2},
{0xefac9e, 0x1a, 0},
{0xefaca0, 0x00, 1},
{0xefaca1, 0x00, 1},
@@ -10066,7 +10065,7 @@ typedef struct
uint32 decomp[2]; /* size of decomposition code list */
} pg_utf_decomposition_size_2;
-static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1591 ] =
+static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1590 ] =
{
{0xc2a8, {0x20, 0xcc88}},
{0xc2af, {0x20, 0xcc84}},
@@ -11273,7 +11272,6 @@ static const pg_utf_decomposition_size_2 UtfDecomp_2 [ 1591 ] =
{0xefac95, {0xd5b4, 0xd5ab}},
{0xefac96, {0xd5be, 0xd5b6}},
{0xefac97, {0xd5b4, 0xd5ad}},
- {0xefac9d, {0xd799, 0xd6b4}},
{0xefad8f, {0xd790, 0xd79c}},
{0xefafaa, {0xd8a6, 0xd8a7}},
{0xefafab, {0xd8a6, 0xd8a7}},
--
2.12.0
On 02/20/2017 01:51 PM, Aleksander Alekseev wrote:
Currently I don't see any significant flaws in these patches. However I
would like to verify that implemented algorithms are compatible with
algorithms implemented by third party.
Yes, that's very important.
For instance, for user 'eax' and password 'pass' I got the following
record in pg_authid:```
scram-sha-256:
xtznkRN/nc/1DQ==:
4096:
2387c124a3139a276b848c910f43ece05dd670d0977ace4f20d724af522312e4:
5e3bdd6584880198b0375acabd8754c460af2389499f71a756660a10a8aaa843
```Let's say I would like to implement SCRAM in pure Python, for instance
add it to pg8000 driver. Firstly I need to know how to generate server
key and client key having only user name and password. Somehow like
this:```
import base64
import hashlib
base64.b16encode(hashlib.pbkdf2_hmac('sha256', b'pass',... base64.b64decode(b'xtznkRN/nc/1DQ=='), 4096))
b'14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3'
```Naturally it doesn't work because both SCRAM_SERVER_KEY_NAME and
SCRAM_CLIENT_KEY_NAME should also be involved. I see PostgreSQL
implementation just in front of me but unfortunately I'm still having
problems calculating exactly the same server key and client key. It makes
me worry whether PostgreSQL implementation is OK.Could you please give an example of how to do it?
RFC5802 describes the protocol in detail:
SaltedPassword := Hi(Normalize(password), salt, i)
ClientKey := HMAC(SaltedPassword, "Client Key")
StoredKey := H(ClientKey)
AuthMessage := client-first-message-bare + "," +
server-first-message + "," +
client-final-message-without-proof
ClientSignature := HMAC(StoredKey, AuthMessage)
ClientProof := ClientKey XOR ClientSignature
ServerKey := HMAC(SaltedPassword, "Server Key")
ServerSignature := HMAC(ServerKey, AuthMessage)
You've calculated SaltedPassword correctly with your Python snippet. To
derive ClientKey from it, you need to pass it to the HMAC() function. In
python, that'd be hmac.new(SaltedPassword, "Client Key",
hashlib.sha256). For example:
```
import base64
import hashlib
import hmac
salt = base64.b64decode(b'xtznkRN/nc/1DQ==');
SaltedPassword = hashlib.pbkdf2_hmac('sha256', b'pass',
salt, 4096);
ClientKey = hmac.new(SaltedPassword, "Client Key",
hashlib.sha256).hexdigest()
print 'SaltedPassword: ' + base64.b16encode(SaltedPassword)
print 'ClientKey; ' + ClientKey
```
This prints:
SaltedPassword:
14B90CFCF690120399A0E6D30C60DD9D9D221CD9C2E31EA0A00514C41823E6C3
ClientKey; 5b681195146a2027cb028a921bd0a89ff858b74bd2b38ed8b42561c28b1e369f
Which matches what the libpq implementation calculated. For constructing
the whole client-final-message, you'll also need to calculate
ClientSignature and ClientProof, which depend on the nonces, and is
therefore different on every authentication exchange.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/02/2017 08:50 AM, Michael Paquier wrote:
Attached is a new patch set. I have combined SASLprep with the rest
and fixed some conflicts. At the same time when going through NFKC
this morning I have noticed that the implementation was doing the
canonical decomposition and reordered the characters using the
combining classes, but the string recomposition was still missing.
This is addressed in this patch set, and well as on my dev tree:
https://github.com/michaelpq/postgres/tree/scram
I've now committed the bulk of these patches. Many thanks to everyone
involved, and especially you, Michael, for your persistence!
There are a bunch of loose ends, like the SASLprep thing. But the core
of this patch has been unchanged for some time now, so it's time to move
ahead.
I left out the new CREATE/ALTER USER ... PASSWORD (... USING '<method>')
syntax, after all. I think that's still a good idea, but it turned out
to be largely orthogonal, and this patch was large enough without it.
Let's discuss that separately, in another thread.
Currently, the AuthenticationSASL protocol message specifies the
mechanism that the client must use, but as future-proofing, it'd
probably be best to redefine that to be a list of mechanisms, and let
the client choose among those. That's not a show-stopper, but would be
good to get that right in version 10, so that clients can prepare for
that, even if we only support one mechanism ATM.
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we
should think about how to extend that too, but I think the proposed
syntax was overly verbose for what we actually support right now. Let's
discuss that as a separate thread, as well.
I didn't commit the TAP authentication tests yet. I just didn't have the
energy to review it all in one go - I will revisit that in the next few
days.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Mar 7, 2017 at 9:36 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I've now committed the bulk of these patches. Many thanks to everyone
involved, and especially you, Michael, for your persistence!
Thanks!
There are a bunch of loose ends, like the SASLprep thing. But the core of
this patch has been unchanged for some time now, so it's time to move ahead.
This is mandatory for Postgres 10. Among all the other subjects this
is high on the list.
I left out the new CREATE/ALTER USER ... PASSWORD (... USING '<method>')
syntax, after all. I think that's still a good idea, but it turned out to be
largely orthogonal, and this patch was large enough without it. Let's
discuss that separately, in another thread.
Without that, we are left with only password_encryption as an option
to create a verifier. I am not sure if people would be fine with this
limitation in PG 10. I'll start a thread tomorrow so let's see.
Currently, the AuthenticationSASL protocol message specifies the mechanism
that the client must use, but as future-proofing, it'd probably be best to
redefine that to be a list of mechanisms, and let the client choose among
those. That's not a show-stopper, but would be good to get that right in
version 10, so that clients can prepare for that, even if we only support
one mechanism ATM.
Yep.
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss that as
a separate thread, as well.
Fine for me.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Mar 7, 2017 at 4:36 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 03/02/2017 08:50 AM, Michael Paquier wrote:
Attached is a new patch set. I have combined SASLprep with the rest
and fixed some conflicts. At the same time when going through NFKC
this morning I have noticed that the implementation was doing the
canonical decomposition and reordered the characters using the
combining classes, but the string recomposition was still missing.
This is addressed in this patch set, and well as on my dev tree:
https://github.com/michaelpq/postgres/tree/scramI've now committed the bulk of these patches. Many thanks to everyone
involved, and especially you, Michael, for your persistence!
+1!
Currently, the AuthenticationSASL protocol message specifies the mechanism
that the client must use, but as future-proofing, it'd probably be best to
redefine that to be a list of mechanisms, and let the client choose among
those. That's not a show-stopper, but would be good to get that right in
version 10, so that clients can prepare for that, even if we only support
one mechanism ATM.
+1, and let's make sure we get it into 10. We don't want to be stuck with
something without flexibility -- then we're going to have to do the whole
"is it time yet" dance again. It would be especially bad since the
underlying protocol is pluggable.
This seems like an obvious place, but are there any other places where we
should also consider something like that for compatibility?
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
On Tue, Mar 07, 2017 at 02:36:13PM +0200, Heikki Linnakangas wrote:
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss that as
a separate thread, as well.
[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item. Heikki,
since you committed the patch believed to have created it, you own this open
item. If some other commit is more relevant or if this does not belong as a
v10 open item, please let us know. Otherwise, please observe the policy on
open item ownership[1]/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com and send a status update within three calendar days of
this message. Include a date for your subsequent status update. Testers may
discover new open items at any time, and I want to plan to get them all fixed
well in advance of shipping v10. Consequently, I will appreciate your efforts
toward speedy resolution. Thanks.
[1]: /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/06/2017 08:36 AM, Noah Misch wrote:
On Tue, Mar 07, 2017 at 02:36:13PM +0200, Heikki Linnakangas wrote:
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss that as
a separate thread, as well.[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item.
I don't think we will come up with anything better than what we have
now, so I have removed this from the open items list.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Apr 06, 2017 at 09:46:29PM +0300, Heikki Linnakangas wrote:
On 04/06/2017 08:36 AM, Noah Misch wrote:
On Tue, Mar 07, 2017 at 02:36:13PM +0200, Heikki Linnakangas wrote:
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss that as
a separate thread, as well.[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item.
I don't think we will come up with anything better than what we have now, so
I have removed this from the open items list.
Michael shared[1]/messages/by-id/CAB7nPqS99Z31f7jhoYYMoBDbuZSQRpn+HQzByA=EwfMDYwCk1Q@mail.gmail.com better pg_hba.conf syntax on 2016-11-05. I agreed[2]/messages/by-id/20170118052356.GA5952@gust with
his framing of the problem and provided two syntax alternatives, on
2017-01-18. Michael implemented[3]/messages/by-id/CAB7nPqSALxkOOHBK3ugBF+Kfq4pqgTgJK_os68f3NkXGhDOz6w@mail.gmail.com a variation of one of those on 2017-02-20,
which you declined in your 2017-03-07 commit with just the explanation quoted
above. I say Michael came up with something better five months ago.
Reserving, as HEAD does today, keyword "scram" to mean "type of SCRAM we
introduced first" will look ugly in 2027. Cryptographic hash functions have a
short shelf life compared to PostgreSQL.
nm
[1]: /messages/by-id/CAB7nPqS99Z31f7jhoYYMoBDbuZSQRpn+HQzByA=EwfMDYwCk1Q@mail.gmail.com
[2]: /messages/by-id/20170118052356.GA5952@gust
[3]: /messages/by-id/CAB7nPqSALxkOOHBK3ugBF+Kfq4pqgTgJK_os68f3NkXGhDOz6w@mail.gmail.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/07/2017 08:21 AM, Noah Misch wrote:
On Thu, Apr 06, 2017 at 09:46:29PM +0300, Heikki Linnakangas wrote:
On 04/06/2017 08:36 AM, Noah Misch wrote:
On Tue, Mar 07, 2017 at 02:36:13PM +0200, Heikki Linnakangas wrote:
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss that as
a separate thread, as well.[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item.
I don't think we will come up with anything better than what we have now, so
I have removed this from the open items list.Michael shared[1] better pg_hba.conf syntax on 2016-11-05. I agreed[2] with
his framing of the problem and provided two syntax alternatives, on
2017-01-18. Michael implemented[3] a variation of one of those on 2017-02-20,
which you declined in your 2017-03-07 commit with just the explanation quoted
above. I say Michael came up with something better five months ago.
OK. My feeling is that we should have a relatively short and
easy-to-pronounce name for it. People editing pg_hba.conf with a text
editor will need to type in the keyword, and "scram" is a lot easier to
remember than "scram-sha-256". The word will also be used in
conversations, "hey, Noah, can you add example.com to the hba file, with
scram, please?" If md5 had a more difficult name, I think we would've
come up with a shorthand for it back in the day, too.
I might be wrong, of course. I don't set up PostgreSQL installations for
a living, so I might be out of touch of what's important.
Reserving, as HEAD does today, keyword "scram" to mean "type of SCRAM we
introduced first" will look ugly in 2027. Cryptographic hash functions have a
short shelf life compared to PostgreSQL.
I don't think that's such a big deal. Firstly, I don't think it would be
too bad for "scram" to mean "the type of SCRAM we introduced first".
Secondly, we can add an alias later, if we add support for a new
mechanism in the SCRAM family.
Our MD5 authentication method was introduced in 2001, I expect
SCRAM-SHA-256 to also last about 15 years before we consider replacing
it. Note that the big problem with our MD5 authentication is not
actually the hash algorithm. There are still no practical pre-image
attacks on MD5, even though it's thoroughly broken for collisions. If we
had "SCRAM-MD5", it would still be OK. So I'd hazard a guess that
whatever will eventually replace SCRAM-SHA-256, will not be SCRAM with a
different hash algorithm, but something else entirely.
The channel binding aspect is actually more important to think about
right now, as that we will hopefully implement in the next release or two.
In [1]/messages/by-id/CAB7nPqS99Z31f7jhoYYMoBDbuZSQRpn+HQzByA=EwfMDYwCk1Q@mail.gmail.com, Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..
It should also be possible to somehow specify "use channel binding, if
the client supports it".
I don't think "sasl" is interesting to a user, it's the actual
mechanisms (e.g "scram-sha256") that matter. So I'd suggest that we
allow a list of algorithms in the method field. If we go with the longer
"scram-sha-256" name, it would look like this:
# TYPE DATABASE USER ADDRESS METHOD
host all all example.com
scram-sha-256-plus, scram-sha-256
The problem again is that those names are quite long. Is that OK?
In [2]/messages/by-id/20170118052356.GA5952@gust, you wrote:
The latest versions document this precisely, but I agree with Peter's concern
about plain "scram". Suppose it's 2025 and PostgreSQL support SASL mechanisms
OAUTHBEARER, SCRAM-SHA-256, SCRAM-SHA-256-PLUS, and SCRAM-SHA3-512. What
should the pg_hba.conf options look like at that time? I don't think having a
single "scram" option fits in such a world. I see two strategies that fit:1. Single "sasl" option, with a GUC, similar to ssl_ciphers, controlling the
mechanisms to offer.
2. Separate options "scram_sha_256", "scram_sha3_512", "oauthbearer", etc.
The example I gave above is like option 2. The problem with option 1 is
that different SASL mechanisms can have very different properties. You
might want to allow "NTLM" from a trusted network, but require "OTP"
from the public internet, for example. So I don't think a single GUC
would be flexible enough.
That said, a GUC with a more narrow scope might be OK. If we called the
method in pg_hba.conf "secure_password", and had a GUC to list which
password-based mechanisms are considered secure, that would be OK. But I
think we'd still need a separate pg_hba.conf method name for
OAUTHBEARER, for example.
PS. If we go with the full names, I think it should "scram-sha-256",
rather than "scram_sha_256", because the official name uses dashes
rather than underscores.
[1]: /messages/by-id/CAB7nPqS99Z31f7jhoYYMoBDbuZSQRpn+HQzByA=EwfMDYwCk1Q@mail.gmail.com
/messages/by-id/CAB7nPqS99Z31f7jhoYYMoBDbuZSQRpn+HQzByA=EwfMDYwCk1Q@mail.gmail.com
[2]: /messages/by-id/20170118052356.GA5952@gust
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jumping late into this one, apologies if these opinions have already been
up and discarded.
On Fri, Apr 7, 2017 at 9:28 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 04/07/2017 08:21 AM, Noah Misch wrote:
On Thu, Apr 06, 2017 at 09:46:29PM +0300, Heikki Linnakangas wrote:
On 04/06/2017 08:36 AM, Noah Misch wrote:
On Tue, Mar 07, 2017 at 02:36:13PM +0200, Heikki Linnakangas wrote:
I didn't include the last-minute changes to the way you specify this in
pg_hba.conf. So it's still just "scram". I agree in general that we
should
think about how to extend that too, but I think the proposed syntax was
overly verbose for what we actually support right now. Let's discuss
that as
a separate thread, as well.[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item.
I don't think we will come up with anything better than what we have
now, so
I have removed this from the open items list.Michael shared[1] better pg_hba.conf syntax on 2016-11-05. I agreed[2]
with
his framing of the problem and provided two syntax alternatives, on
2017-01-18. Michael implemented[3] a variation of one of those on
2017-02-20,
which you declined in your 2017-03-07 commit with just the explanation
quoted
above. I say Michael came up with something better five months ago.OK. My feeling is that we should have a relatively short and
easy-to-pronounce name for it. People editing pg_hba.conf with a text
editor will need to type in the keyword, and "scram" is a lot easier to
remember than "scram-sha-256". The word will also be used in conversations,
"hey, Noah, can you add example.com to the hba file, with scram, please?"
If md5 had a more difficult name, I think we would've come up with a
shorthand for it back in the day, too.I might be wrong, of course. I don't set up PostgreSQL installations for a
living, so I might be out of touch of what's important.Reserving, as HEAD does today, keyword "scram" to mean "type of SCRAM we
introduced first" will look ugly in 2027. Cryptographic hash functions
have a
short shelf life compared to PostgreSQL.I don't think that's such a big deal. Firstly, I don't think it would be
too bad for "scram" to mean "the type of SCRAM we introduced first".
Secondly, we can add an alias later, if we add support for a new mechanism
in the SCRAM family.Our MD5 authentication method was introduced in 2001, I expect
SCRAM-SHA-256 to also last about 15 years before we consider replacing it.
Note that the big problem with our MD5 authentication is not actually the
hash algorithm. There are still no practical pre-image attacks on MD5, even
though it's thoroughly broken for collisions. If we had "SCRAM-MD5", it
would still be OK. So I'd hazard a guess that whatever will eventually
replace SCRAM-SHA-256, will not be SCRAM with a different hash algorithm,
but something else entirely.
So here's a wild idea. What if we just call it "sha256"? Does the user
actually care about it being scram, or is scram just an implementation
detail for them? That way when the next one shows up, it'll be sha512 or
whatever. It happens to use scram under the hood, but does the user have to
or does the user want to care about that?
(One could argue the same way that the user shouldn't have to or want to
care about the hashing algorithm -- but if that's the case then we should
only have one entry, it would be "scram", and the system would decide from
there. And I think this discussion already indicates we don't think this is
enough)
The channel binding aspect is actually more important to think about right
now, as that we will hopefully implement in the next release or two.In [1], Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel binding, if the
client supports it".
Is that really a type of authentication? We already hvae the idea of
authentication method options, used for most other things except md5 which
doesn't have any. So it could be "sha256 channelbind=on", "sha256
channelbind=off" or "sha256 channelbind=negotiate" or something like that?
I don't think "sasl" is interesting to a user, it's the actual mechanisms
(e.g "scram-sha256") that matter. So I'd suggest that we allow a list of
algorithms in the method field. If we go with the longer "scram-sha-256"
name, it would look like this:# TYPE DATABASE USER ADDRESS METHOD
host all all example.com scram-sha-256-plus,
scram-sha-256The problem again is that those names are quite long. Is that OK?
Not sure if it would be doable in the code, but we could also have:
host all all example.com scram method=sha256plus,sha256
or something like that. Which would fit within the current syntax of the
file. But I think it might not be enough, because then you couldn't have
two entries with different scram methods for the same combination of the
other fields -- the hba *matching* doesn't look at the options fields.
In [2], you wrote:
The latest versions document this precisely, but I agree with Peter's
concern
about plain "scram". Suppose it's 2025 and PostgreSQL support SASL
mechanisms
OAUTHBEARER, SCRAM-SHA-256, SCRAM-SHA-256-PLUS, and SCRAM-SHA3-512. What
should the pg_hba.conf options look like at that time? I don't think
having a
single "scram" option fits in such a world. I see two strategies that
fit:1. Single "sasl" option, with a GUC, similar to ssl_ciphers, controlling
the
mechanisms to offer.
2. Separate options "scram_sha_256", "scram_sha3_512", "oauthbearer", etc.The example I gave above is like option 2. The problem with option 1 is
that different SASL mechanisms can have very different properties. You
might want to allow "NTLM" from a trusted network, but require "OTP" from
the public internet, for example. So I don't think a single GUC would be
flexible enough.
+1.
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
On 04/07/2017 10:38 AM, Magnus Hagander wrote:
So here's a wild idea. What if we just call it "sha256"? Does the user
actually care about it being scram, or is scram just an implementation
detail for them? That way when the next one shows up, it'll be sha512 or
whatever. It happens to use scram under the hood, but does the user have to
or does the user want to care about that?(One could argue the same way that the user shouldn't have to or want to
care about the hashing algorithm -- but if that's the case then we should
only have one entry, it would be "scram", and the system would decide from
there. And I think this discussion already indicates we don't think this is
enough)
I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
The main against using just "scram" is that it's misleading, because we
implement SCRAM-SHA-256, rather than SCRAM-SHA-1, which was the first
SCRAM mechanism, commonly called just SCRAM. As long as that's the only
SCRAM variant we have, that's not too bad, but it becomes more confusing
if we ever implement SCRAM-SHA-512 or SCRAM-something-else in the
future. That's the point Noah made, and it's a fair point, but the
question is whether we consider that to be more important than having a
short name for what we have now.
The channel binding aspect is actually more important to think about right
now, as that we will hopefully implement in the next release or two.In [1], Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel binding, if the
client supports it".Is that really a type of authentication? We already hvae the idea of
authentication method options, used for most other things except md5 which
doesn't have any. So it could be "sha256 channelbind=on", "sha256
channelbind=off" or "sha256 channelbind=negotiate" or something like that?
Technically, the channel-binding variant is a separate SASL mechanism,
i.e. it has a separate name, SCRAM-SHA-256-PLUS. I'm not sure if
users/admins think of it that way.
I don't think "sasl" is interesting to a user, it's the actual mechanisms
(e.g "scram-sha256") that matter. So I'd suggest that we allow a list of
algorithms in the method field. If we go with the longer "scram-sha-256"
name, it would look like this:# TYPE DATABASE USER ADDRESS METHOD
host all all example.com scram-sha-256-plus,
scram-sha-256The problem again is that those names are quite long. Is that OK?
Not sure if it would be doable in the code, but we could also have:
host all all example.com scram method=sha256plus,sha256or something like that. Which would fit within the current syntax of the
file. But I think it might not be enough, because then you couldn't have
two entries with different scram methods for the same combination of the
other fields -- the hba *matching* doesn't look at the options fields.
You can't have two entries with the same type+database+user+address
combination, period. (Or if you do, the second one is ignored.)
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 7 April 2017 at 15:59, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 04/07/2017 10:38 AM, Magnus Hagander wrote:
Not sure if it would be doable in the code, but we could also have:
host all all example.com scram method=sha256plus,sha256or something like that. Which would fit within the current syntax of the
file. But I think it might not be enough, because then you couldn't have
two entries with different scram methods for the same combination of the
other fields -- the hba *matching* doesn't look at the options fields.You can't have two entries with the same type+database+user+address
combination, period. (Or if you do, the second one is ignored.)
So we need a methods= list for users who want to constrain the allowed
methods, accepting a list of methods. This is just how things like SSH
work; e.g. ssh_config might contain
Ciphers aes128-cbc,3des-cbc
if you feel like using the old dodgy stuff today.
If the user doesn't supply a methods= list, they get a full list of
supported methods by the server to choose from in the 'B' message, and
can auth with any one of them.
I'm aware there are some compat concerns there, but existing clients
will already have no idea what the scram method is, so now's our
chance to lock it in as containing a *list* of permitted methods. Even
though to start with it it's hard coded.
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Apr 7, 2017 at 9:59 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 04/07/2017 10:38 AM, Magnus Hagander wrote:
So here's a wild idea. What if we just call it "sha256"? Does the user
actually care about it being scram, or is scram just an implementation
detail for them? That way when the next one shows up, it'll be sha512 or
whatever. It happens to use scram under the hood, but does the user have
to
or does the user want to care about that?(One could argue the same way that the user shouldn't have to or want to
care about the hashing algorithm -- but if that's the case then we should
only have one entry, it would be "scram", and the system would decide from
there. And I think this discussion already indicates we don't think this
is
enough)I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
If that is the important part, then I agree :) I am not entirely sure that
the scram part *is* more important though.
I think most users will be a lot more comfortable with "sha256" than
"scram" though. But I guess that says using scram-sha-256 is the correct
way.
The main against using just "scram" is that it's misleading, because we
implement SCRAM-SHA-256, rather than SCRAM-SHA-1, which was the first SCRAM
mechanism, commonly called just SCRAM. As long as that's the only SCRAM
variant we have, that's not too bad, but it becomes more confusing if we
ever implement SCRAM-SHA-512 or SCRAM-something-else in the future. That's
the point Noah made, and it's a fair point, but the question is whether we
consider that to be more important than having a short name for what we
have now.
Yeah, I agree we should be prepared for the future. And having "scram" and
"scram-sha-512" would definitely fall under confusing.
The channel binding aspect is actually more important to think about right
now, as that we will hopefully implement in the next release or two.
In [1], Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel binding, if the
client supports it".Is that really a type of authentication? We already hvae the idea of
authentication method options, used for most other things except md5 which
doesn't have any. So it could be "sha256 channelbind=on", "sha256
channelbind=off" or "sha256 channelbind=negotiate" or something like that?
Technically, the channel-binding variant is a separate SASL mechanism,
i.e. it has a separate name, SCRAM-SHA-256-PLUS. I'm not sure if >
users/admins think of it that way.
I bet they don't.
I don't think "sasl" is interesting to a user, it's the actual mechanisms
(e.g "scram-sha256") that matter. So I'd suggest that we allow a list of
algorithms in the method field. If we go with the longer "scram-sha-256"
name, it would look like this:# TYPE DATABASE USER ADDRESS METHOD
host all all example.com scram-sha-256-plus,
scram-sha-256The problem again is that those names are quite long. Is that OK?
Not sure if it would be doable in the code, but we could also have:
host all all example.com scram method=sha256plus,sha256or something like that. Which would fit within the current syntax of the
file. But I think it might not be enough, because then you couldn't have
two entries with different scram methods for the same combination of the
other fields -- the hba *matching* doesn't look at the options fields.
You can't have two entries with the same type+database+user+address
combination, period. (Or if you do, the second one is ignored.)
That's exactly my point.
//Magnus
On 07/04/17 11:05, Magnus Hagander wrote:
On Fri, Apr 7, 2017 at 9:59 AM, Heikki Linnakangas <hlinnaka@iki.fi
<mailto:hlinnaka@iki.fi>> wrote:On 04/07/2017 10:38 AM, Magnus Hagander wrote:
So here's a wild idea. What if we just call it "sha256"? Does
the user
actually care about it being scram, or is scram just an
implementation
detail for them? That way when the next one shows up, it'll be
sha512 or
whatever. It happens to use scram under the hood, but does the
user have to
or does the user want to care about that?(One could argue the same way that the user shouldn't have to
or want to
care about the hashing algorithm -- but if that's the case
then we should
only have one entry, it would be "scram", and the system would
decide from
there. And I think this discussion already indicates we don't
think this is
enough)I think the "SCRAM" part is more important than "SHA-256", so -1
on that.If that is the important part, then I agree :) I am not entirely sure
that the scram part *is* more important though.
I agree it is much more important. Needed, I'd say. "SHA-256" could
refer to other mechanisms that just simply hash the value (maybe with a
salt, or not) with that hash algorithm. SCRAM is a different beast, with
much more functionality than that. So yes, it matters a lot :)
I think most users will be a lot more comfortable with "sha256" than
"scram" though. But I guess that says using scram-sha-256 is the
correct way.
I don't like UPPERCASE, but the RFC links to the IANA registry
where SCRAM methods are all uppercase and with dashes: SCRAM-SHA-256 and
SCRAM-SHA-256-PLUS. I'd use those names, they are standardized.
The main against using just "scram" is that it's misleading,
because we implement SCRAM-SHA-256, rather than SCRAM-SHA-1, which
was the first SCRAM mechanism, commonly called just SCRAM. As long
as that's the only SCRAM variant we have, that's not too bad, but
it becomes more confusing if we ever implement SCRAM-SHA-512 or
SCRAM-something-else in the future. That's the point Noah made,
and it's a fair point, but the question is whether we consider
that to be more important than having a short name for what we
have now.Yeah, I agree we should be prepared for the future. And having "scram"
and "scram-sha-512" would definitely fall under confusing.The channel binding aspect is actually more important to think
about right
now, as that we will hopefully implement in the next release
or two.In [1], Michael wrote:
There is also the channel binding to think about... So we
could have a
list of keywords perhaps associated with SASL? Imagine for
example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first
entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course
other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel
binding, if the
client supports it".Is that really a type of authentication? We already hvae the idea of
authentication method options, used for most other things except
md5 which
doesn't have any. So it could be "sha256 channelbind=on", "sha256
channelbind=off" or "sha256 channelbind=negotiate" or something
like that?Technically, the channel-binding variant is a separate SASL
mechanism, i.e. it has a separate name, SCRAM-SHA-256-PLUS. I'm not
sure if > users/admins think of it that way.I bet they don't.
Probably. But let's not underestimate channel binding: it is the
"greatest" feature of SCRAM, and where security really shines. I'd
encourage the use of channel binding and would definitely make it explicit.
As for the options, there's no way to negotiate, the client picks.
It could still be three-valued: on, off, only-channel-binding (or
however you want to call them). That will only change what mechanisms
the server will be advertising to clients.
Álvaro
--
Álvaro Hernández Tortosa
-----------
<8K>data
On Fri, Apr 7, 2017 at 3:59 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
I agree. The point here isn't that we're using a better hashing
method, even if a lot of people *think* that's the point. The point
is we're using a modern algorithm that has nice properties like "you
can't impersonate the client by steeling the verifier, or even by
snooping the exchange".
But "sasl" might be even better.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Apr 8, 2017 at 1:59 AM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Apr 7, 2017 at 3:59 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
I agree. The point here isn't that we're using a better hashing
method, even if a lot of people *think* that's the point. The point
is we're using a modern algorithm that has nice properties like "you
can't impersonate the client by steeling the verifier, or even by
snooping the exchange".But "sasl" might be even better.
FWIW, my opinion has not changed much on the matter, I would still
favor "sasl" as the keyword used in pg_hba.conf. What has changed in
my mind though is that defining no mechanisms with an additional
option mean that all possible choices are sent to the client. But if
you define a list of mechanisms, then we'll just send back to the
client the specified list as a possible choice of exchange mechanism:
host all all blah.com sasl mechanism=scram-sha-256-plus
Here for example the user would not be allowed to use SCRAM-SHA-256,
just SCRAM with channel binding.
Such an option makes sense once we add support for one more mechanism
in SASL, like channel binding, but that's by far a generic approach
that can serve us for years to come, and by admitting that nothing
listed means all possible options we don't need any immediate action.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Apr 7, 2017 at 6:32 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Sat, Apr 8, 2017 at 1:59 AM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Apr 7, 2017 at 3:59 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
I agree. The point here isn't that we're using a better hashing
method, even if a lot of people *think* that's the point. The point
is we're using a modern algorithm that has nice properties like "you
can't impersonate the client by steeling the verifier, or even by
snooping the exchange".But "sasl" might be even better.
FWIW, my opinion has not changed much on the matter, I would still
favor "sasl" as the keyword used in pg_hba.conf. What has changed in
my mind though is that defining no mechanisms with an additional
option mean that all possible choices are sent to the client. But if
you define a list of mechanisms, then we'll just send back to the
client the specified list as a possible choice of exchange mechanism:
host all all blah.com sasl mechanism=scram-sha-256-plus
Here for example the user would not be allowed to use SCRAM-SHA-256,
just SCRAM with channel binding.Such an option makes sense once we add support for one more mechanism
in SASL, like channel binding, but that's by far a generic approach
that can serve us for years to come, and by admitting that nothing
listed means all possible options we don't need any immediate action.
Yes, that all seems quite sensible. What exactly is the counter-argument?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Apr 07, 2017 at 10:28:59AM +0300, Heikki Linnakangas wrote:
On 04/07/2017 08:21 AM, Noah Misch wrote:
Michael shared[1] better pg_hba.conf syntax on 2016-11-05. I agreed[2] with
his framing of the problem and provided two syntax alternatives, on
2017-01-18. Michael implemented[3] a variation of one of those on 2017-02-20,
which you declined in your 2017-03-07 commit with just the explanation quoted
above. I say Michael came up with something better five months ago.OK. My feeling is that we should have a relatively short and
easy-to-pronounce name for it. People editing pg_hba.conf with a text editor
will need to type in the keyword, and "scram" is a lot easier to remember
than "scram-sha-256". The word will also be used in conversations, "hey,
Noah, can you add example.com to the hba file, with scram, please?" If md5
had a more difficult name, I think we would've come up with a shorthand for
it back in the day, too.I might be wrong, of course. I don't set up PostgreSQL installations for a
living, so I might be out of touch of what's important.
Likewise, but I've never seen pg_hba.conf edits become a large slice of
PostgreSQL DBA work. Whereas experts can appreciate terse query syntax,
pg_hba.conf syntax gains little from terseness.
In [1], Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel binding, if the
client supports it".I don't think "sasl" is interesting to a user, it's the actual mechanisms
(e.g "scram-sha256") that matter. So I'd suggest that we allow a list of
algorithms in the method field. If we go with the longer "scram-sha-256"
name, it would look like this:# TYPE DATABASE USER ADDRESS METHOD
host all all example.com scram-sha-256-plus,
scram-sha-256
I agree "sasl" focuses on a less-interesting aspect of the authentication
method. Allowing multiple methods per HBA line may be the better answer, so
long as the policy questions it raises aren't too thorny. Do you allow any
combination of methods or limit it somehow (e.g. only SASL methods)? If the
same option pertains to two methods, do we provide a way to set the option on
just one method? Those don't seem too challenging, though.
The problem again is that those names are quite long. Is that OK?
Yes.
With this, you could have a meta-method name (e.g. "default") that stands for
all methods generally considered safe. Compare SSL default cipher lists.
In [2], you wrote:
The latest versions document this precisely, but I agree with Peter's concern
about plain "scram". Suppose it's 2025 and PostgreSQL support SASL mechanisms
OAUTHBEARER, SCRAM-SHA-256, SCRAM-SHA-256-PLUS, and SCRAM-SHA3-512. What
should the pg_hba.conf options look like at that time? I don't think having a
single "scram" option fits in such a world. I see two strategies that fit:1. Single "sasl" option, with a GUC, similar to ssl_ciphers, controlling the
mechanisms to offer.
2. Separate options "scram_sha_256", "scram_sha3_512", "oauthbearer", etc.The example I gave above is like option 2. The problem with option 1 is that
different SASL mechanisms can have very different properties. You might want
to allow "NTLM" from a trusted network, but require "OTP" from the public
internet, for example. So I don't think a single GUC would be flexible
enough.That said, a GUC with a more narrow scope might be OK. If we called the
method in pg_hba.conf "secure_password", and had a GUC to list which
password-based mechanisms are considered secure, that would be OK. But I
think we'd still need a separate pg_hba.conf method name for OAUTHBEARER,
for example.
Michael replied to my message with the idea to use a mechanism= HBA option.
That's better than a GUC.
PS. If we go with the full names, I think it should "scram-sha-256", rather
than "scram_sha_256", because the official name uses dashes rather than
underscores.
Agreed, I don't remember why I wrote underscores. One could argue on that
basis for using uppercase, but I won't.
These are the two chief approaches I'm seeing:
1. scram-sha-256, scram-sha-256-plus, and successors will be their own
pg_hba.conf authentication methods. Until and unless someone implements an
ability to name multiple methods per HBA line, you must choose exactly one
SASL method. The concrete work for v10 would be merely renaming "scram" to
"scram-sha-256".
2. Create a multiplexed authentication method like "sasl" or "scram" (not to
be confused with today's "scram" method, which denotes SCRAM-SHA-256
precisely). The DBA permits concrete methods like scram-sha-256 via HBA
option. Absent that option, the system could default to a reasonable list.
I had been favoring (2), but I'm starting to like (1) more. (2) assumes all
SASL methods or all SCRAM methods have something in common with each other and
not with other methods, and that's not so. For example, one might implement
simultaneous md5 and scram-sha-256. (1) is harder to implement, but we can
defer that work indefinitely.
Thanks,
nm
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Apr 8, 2017 at 9:28 AM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Apr 7, 2017 at 6:32 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Sat, Apr 8, 2017 at 1:59 AM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Apr 7, 2017 at 3:59 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
I think the "SCRAM" part is more important than "SHA-256", so -1 on that.
I agree. The point here isn't that we're using a better hashing
method, even if a lot of people *think* that's the point. The point
is we're using a modern algorithm that has nice properties like "you
can't impersonate the client by steeling the verifier, or even by
snooping the exchange".But "sasl" might be even better.
FWIW, my opinion has not changed much on the matter, I would still
favor "sasl" as the keyword used in pg_hba.conf. What has changed in
my mind though is that defining no mechanisms with an additional
option mean that all possible choices are sent to the client. But if
you define a list of mechanisms, then we'll just send back to the
client the specified list as a possible choice of exchange mechanism:
host all all blah.com sasl mechanism=scram-sha-256-plus
Here for example the user would not be allowed to use SCRAM-SHA-256,
just SCRAM with channel binding.Such an option makes sense once we add support for one more mechanism
in SASL, like channel binding, but that's by far a generic approach
that can serve us for years to come, and by admitting that nothing
listed means all possible options we don't need any immediate action.Yes, that all seems quite sensible. What exactly is the counter-argument?
I am unsure what that argument is either by reading the thread again.
Attached is a patch to hopefully make the discussion progress. I
simply propose to use sasl as a keyword for pg_hba.conf, on the basis
that SASL is the protocol used, and scram is a mechanism used to
achieve the SASL exchange. We can always come up with a set of options
and aliases later, I am actually open to have more fancy extra options
in pg_hba.conf.
Here is my original proposal:
sasl mechanism=scram-sha-256-plus,scram-sha-256
But we could have something like that as well:
sasl mechanism=scram-plus,scram
sasl mechanism=scram channel_binding=on/off
A problem with the last one is that it is not possible to control
channel binding per mechanism, but that could be discussed later on
once support for channel binding is added. For now I would just favor
the most extensive approach. No need to work later on with some
aliases in pg_hba.conf either.
--
Michael
Attachments:
reshape-sasl-hba.patchapplication/octet-stream; name=reshape-sasl-hba.patchDownload
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index c2fc6d3261..4fb0aebb66 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -412,11 +412,12 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</varlistentry>
<varlistentry>
- <term><literal>scram</></term>
+ <term><literal>sasl</></term>
<listitem>
<para>
- Perform SCRAM-SHA-256 authentication to verify the user's
- password. See <xref linkend="auth-password"> for details.
+ Perform SASL authentication to verify the user's password. See
+ <xref linkend="auth-password"> for details. The only mechanism
+ supported currently is SCRAM-SHA-256.
</para>
</listitem>
</varlistentry>
@@ -425,7 +426,7 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
<term><literal>md5</></term>
<listitem>
<para>
- Perform SCRAM-SHA-256 or MD5 authentication to verify the
+ Perform SASL or MD5 authentication to verify the
user's password. See <xref linkend="auth-password">
for details.
</para>
@@ -683,18 +684,18 @@ host postgres all 192.168.93.0/24 ident
# "postgres" if the user's password is correctly supplied.
#
# TYPE DATABASE USER ADDRESS METHOD
-host postgres all 192.168.12.10/32 scram
+host postgres all 192.168.12.10/32 sasl
# Allow any user from hosts in the example.com domain to connect to
# any database if the user's password is correctly supplied.
#
-# Require SCRAM authentication for most users, but make an exception
-# for user 'mike', who uses an older client that doesn't support SCRAM
+# Require SASL authentication for most users, but make an exception
+# for user 'mike', who uses an older client that doesn't support SASL
# authentication.
#
# TYPE DATABASE USER ADDRESS METHOD
-host all mike .example.com md5
-host all all .example.com scram
+host all mike .example.com sasl
+host all all .example.com sasl
# In the absence of preceding "host" lines, these two lines will
# reject all connections from 192.168.54.1 (since that entry will be
@@ -922,7 +923,7 @@ omicron bryanh guest1
</indexterm>
<para>
- The password-based authentication methods are <literal>scram</>
+ The password-based authentication methods are <literal>sasl</>
<literal>md5</> and <literal>password</>. These methods operate
similarly except for the way that the password is sent across the
connection.
@@ -939,8 +940,9 @@ omicron bryanh guest1
<para>
- <literal>scram</> performs SCRAM-SHA-256 authentication, as described
- in <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink>. It
+ <literal>sasl</> performs SASL authentication using SCRAM-SHA-256 as
+ mechanism, as described in
+ <ulink url="https://tools.ietf.org/html/rfc5802">RFC5802</ulink>. It
is a challenge-response scheme, that prevents password sniffing on
untrusted connections. It is more secure than the <literal>md5</>
method, but might not be supported by older clients.
@@ -953,7 +955,7 @@ omicron bryanh guest1
protection if an attacker manages to steal the password hash from the
server, and it cannot be used with the <xref
linkend="guc-db-user-namespace"> feature. For all other users,
- <literal>md5</> works the same as <literal>scram</>.
+ <literal>md5</> works the same as <literal>sasl</>.
</para>
<para>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index a3c6c6d8b3..aa52d2e90f 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -57,7 +57,7 @@ static int CheckPasswordAuth(Port *port, char **logdetail);
static int CheckPWChallengeAuth(Port *port, char **logdetail);
static int CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail);
-static int CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail);
+static int CheckSASLAuth(Port *port, char *shadow_pass, char **logdetail);
/*----------------------------------------------------------------
@@ -284,7 +284,7 @@ auth_failed(Port *port, int status, char *logdetail)
break;
case uaPassword:
case uaMD5:
- case uaSCRAM:
+ case uaSASL:
errstr = gettext_noop("password authentication failed for user \"%s\"");
/* We use it to indicate if a .pgpass password failed. */
errcode_return = ERRCODE_INVALID_PASSWORD;
@@ -545,7 +545,7 @@ ClientAuthentication(Port *port)
break;
case uaMD5:
- case uaSCRAM:
+ case uaSASL:
status = CheckPWChallengeAuth(port, &logdetail);
break;
@@ -737,7 +737,7 @@ CheckPasswordAuth(Port *port, char **logdetail)
}
/*
- * MD5 and SCRAM authentication.
+ * MD5 and SASL authentication.
*/
static int
CheckPWChallengeAuth(Port *port, char **logdetail)
@@ -746,7 +746,7 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
char *shadow_pass;
PasswordType pwtype;
- Assert(port->hba->auth_method == uaSCRAM ||
+ Assert(port->hba->auth_method == uaSASL ||
port->hba->auth_method == uaMD5);
/* First look up the user's password. */
@@ -774,12 +774,12 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
* If 'md5' authentication is allowed, decide whether to perform 'md5' or
* 'scram' authentication based on the type of password the user has. If
* it's an MD5 hash, we must do MD5 authentication, and if it's a SCRAM
- * verifier, we must do SCRAM authentication. If it's stored in
+ * verifier, we must do SASL authentication. If it's stored in
* plaintext, we could do either one, so we opt for the more secure
* mechanism, SCRAM.
*
* If MD5 authentication is not allowed, always use SCRAM. If the user
- * had an MD5 password, CheckSCRAMAuth() will fail.
+ * had an MD5 password, CheckSASLAuth() will fail.
*/
if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5)
{
@@ -787,7 +787,7 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
}
else
{
- auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail);
+ auth_result = CheckSASLAuth(port, shadow_pass, logdetail);
}
if (shadow_pass)
@@ -843,7 +843,7 @@ CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail)
}
static int
-CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
+CheckSASLAuth(Port *port, char *shadow_pass, char **logdetail)
{
int mtype;
StringInfoData buf;
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index af89fe898a..194a94485c 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -126,7 +126,7 @@ static const char *const UserAuthName[] =
"ident",
"password",
"md5",
- "scram",
+ "sasl",
"gss",
"sspi",
"pam",
@@ -1327,8 +1327,8 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
}
parsedline->auth_method = uaMD5;
}
- else if (strcmp(token->string, "scram") == 0)
- parsedline->auth_method = uaSCRAM;
+ else if (strcmp(token->string, "sasl") == 0)
+ parsedline->auth_method = uaSASL;
else if (strcmp(token->string, "pam") == 0)
#ifdef USE_PAM
parsedline->auth_method = uaPAM;
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 6b1778a721..96119a9022 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -42,9 +42,9 @@
# or "samenet" to match any address in any subnet that the server is
# directly connected to.
#
-# METHOD can be "trust", "reject", "md5", "password", "scram", "gss",
+# METHOD can be "trust", "reject", "md5", "password", "sasl", "gss",
# "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
-# "password" sends passwords in clear text; "md5" or "scram" are preferred
+# "password" sends passwords in clear text; "md5" or "sasl" are preferred
# since they send encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index d40ed412fc..0874d2cd3a 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -77,7 +77,7 @@
extern const char *select_default_timezone(const char *share_path);
static const char *const auth_methods_host[] = {
- "trust", "reject", "md5", "password", "scram", "ident", "radius",
+ "trust", "reject", "md5", "password", "sasl", "ident", "radius",
#ifdef ENABLE_GSS
"gss",
#endif
@@ -99,7 +99,7 @@ static const char *const auth_methods_host[] = {
NULL
};
static const char *const auth_methods_local[] = {
- "trust", "reject", "md5", "scram", "password", "peer", "radius",
+ "trust", "reject", "md5", "sasl", "password", "peer", "radius",
#ifdef USE_PAM
"pam", "pam ",
#endif
@@ -1130,8 +1130,8 @@ setup_config(void)
"#update_process_title = off");
#endif
- if (strcmp(authmethodlocal, "scram") == 0 ||
- strcmp(authmethodhost, "scram") == 0)
+ if (strcmp(authmethodlocal, "sasl") == 0 ||
+ strcmp(authmethodhost, "sasl") == 0)
{
conflines = replace_token(conflines,
"#password_encryption = md5",
@@ -2329,16 +2329,16 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost)
{
if ((strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0) &&
+ strcmp(authmethodlocal, "sasl") == 0) &&
(strcmp(authmethodhost, "md5") == 0 ||
strcmp(authmethodhost, "password") == 0 ||
- strcmp(authmethodhost, "scram") == 0) &&
+ strcmp(authmethodhost, "sasl") == 0) &&
!(pwprompt || pwfilename))
{
fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
(strcmp(authmethodlocal, "md5") == 0 ||
strcmp(authmethodlocal, "password") == 0 ||
- strcmp(authmethodlocal, "scram") == 0)
+ strcmp(authmethodlocal, "sasl") == 0)
? authmethodlocal
: authmethodhost);
exit(1);
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 9a4f228d6a..6c7382e67f 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -30,7 +30,7 @@ typedef enum UserAuth
uaIdent,
uaPassword,
uaMD5,
- uaSCRAM,
+ uaSASL,
uaGSS,
uaSSPI,
uaPAM,
diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl
index d7bc13bd58..5731818e37 100644
--- a/src/test/authentication/t/001_password.pl
+++ b/src/test/authentication/t/001_password.pl
@@ -68,12 +68,12 @@ SKIP:
test_role($node, 'md5_role', 'password', 0);
test_role($node, 'plain_role', 'password', 0);
- # For "scram" method, user "plain_role" and "scram_role" should be able to
+ # For "sasl" method, user "plain_role" and "scram_role" should be able to
# connect.
- reset_pg_hba($node, 'scram');
- test_role($node, 'scram_role', 'scram', 0);
- test_role($node, 'md5_role', 'scram', 2);
- test_role($node, 'plain_role', 'scram', 0);
+ reset_pg_hba($node, 'sasl');
+ test_role($node, 'scram_role', 'sasl', 0);
+ test_role($node, 'md5_role', 'sasl', 2);
+ test_role($node, 'plain_role', 'sasl', 0);
# For "md5" method, all users should be able to connect (SCRAM
# authentication will be performed for the user with a scram verifier.)
diff --git a/src/test/authentication/t/002_saslprep.pl b/src/test/authentication/t/002_saslprep.pl
index 7e373ed7bf..98d4c21b4f 100644
--- a/src/test/authentication/t/002_saslprep.pl
+++ b/src/test/authentication/t/002_saslprep.pl
@@ -73,7 +73,7 @@ SKIP:
");
# Require password from now on.
- reset_pg_hba($node, 'scram');
+ reset_pg_hba($node, 'sasl');
# Check that #1 and #5 are treated the same as just 'IX'
test_login($node, 'saslpreptest1_role', "I\xc2\xadX", 0);
On 10 April 2017 at 12:34, Michael Paquier <michael.paquier@gmail.com> wrote:
Attached is a patch to hopefully make the discussion progress. I
simply propose to use sasl as a keyword for pg_hba.conf, on the basis
that SASL is the protocol used, and scram is a mechanism used to
achieve the SASL exchange. We can always come up with a set of options
and aliases later, I am actually open to have more fancy extra options
in pg_hba.conf.
I'd really like to see this approach proceed.
pg_hba.conf isn't the most user-friendly thing in the world, and seems
to be one of the top sources of confusion for new users. Simple is
good here IMO.
Let users specify 'scram' and negotiate.
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10 April 2017 at 13:57, Craig Ringer <craig@2ndquadrant.com> wrote:
On 10 April 2017 at 12:34, Michael Paquier <michael.paquier@gmail.com> wrote:
Attached is a patch to hopefully make the discussion progress. I
simply propose to use sasl as a keyword for pg_hba.conf, on the basis
that SASL is the protocol used, and scram is a mechanism used to
achieve the SASL exchange. We can always come up with a set of options
and aliases later, I am actually open to have more fancy extra options
in pg_hba.conf.I'd really like to see this approach proceed.
pg_hba.conf isn't the most user-friendly thing in the world, and seems
to be one of the top sources of confusion for new users. Simple is
good here IMO.Let users specify 'scram' and negotiate.
sasl, rather.
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/10/2017 02:19 AM, Noah Misch wrote:
On Fri, Apr 07, 2017 at 10:28:59AM +0300, Heikki Linnakangas wrote:
On 04/07/2017 08:21 AM, Noah Misch wrote:
Michael shared[1] better pg_hba.conf syntax on 2016-11-05. I agreed[2] with
his framing of the problem and provided two syntax alternatives, on
2017-01-18. Michael implemented[3] a variation of one of those on 2017-02-20,
which you declined in your 2017-03-07 commit with just the explanation quoted
above. I say Michael came up with something better five months ago.OK. My feeling is that we should have a relatively short and
easy-to-pronounce name for it. People editing pg_hba.conf with a text editor
will need to type in the keyword, and "scram" is a lot easier to remember
than "scram-sha-256". The word will also be used in conversations, "hey,
Noah, can you add example.com to the hba file, with scram, please?" If md5
had a more difficult name, I think we would've come up with a shorthand for
it back in the day, too.I might be wrong, of course. I don't set up PostgreSQL installations for a
living, so I might be out of touch of what's important.Likewise, but I've never seen pg_hba.conf edits become a large slice of
PostgreSQL DBA work. Whereas experts can appreciate terse query syntax,
pg_hba.conf syntax gains little from terseness.In [1], Michael wrote:
There is also the channel binding to think about... So we could have a
list of keywords perhaps associated with SASL? Imagine for example:
sasl $algo,$channel_binding
Giving potentially:
sasl scram_sha256
sasl scram_sha256,channel
sasl scram_sha512
sasl scram_sha512,channel
In the case of the patch of this thread just the first entry would
make sense, once channel binding support is added a second
keyword/option could be added. And there are of course other methods
that could replace SCRAM..It should also be possible to somehow specify "use channel binding, if the
client supports it".I don't think "sasl" is interesting to a user, it's the actual mechanisms
(e.g "scram-sha256") that matter. So I'd suggest that we allow a list of
algorithms in the method field. If we go with the longer "scram-sha-256"
name, it would look like this:# TYPE DATABASE USER ADDRESS METHOD
host all all example.com scram-sha-256-plus,
scram-sha-256I agree "sasl" focuses on a less-interesting aspect of the authentication
method. Allowing multiple methods per HBA line may be the better answer, so
long as the policy questions it raises aren't too thorny. Do you allow any
combination of methods or limit it somehow (e.g. only SASL methods)? If the
same option pertains to two methods, do we provide a way to set the option on
just one method? Those don't seem too challenging, though.The problem again is that those names are quite long. Is that OK?
Yes.
With this, you could have a meta-method name (e.g. "default") that stands for
all methods generally considered safe. Compare SSL default cipher lists.In [2], you wrote:
The latest versions document this precisely, but I agree with Peter's concern
about plain "scram". Suppose it's 2025 and PostgreSQL support SASL mechanisms
OAUTHBEARER, SCRAM-SHA-256, SCRAM-SHA-256-PLUS, and SCRAM-SHA3-512. What
should the pg_hba.conf options look like at that time? I don't think having a
single "scram" option fits in such a world. I see two strategies that fit:1. Single "sasl" option, with a GUC, similar to ssl_ciphers, controlling the
mechanisms to offer.
2. Separate options "scram_sha_256", "scram_sha3_512", "oauthbearer", etc.The example I gave above is like option 2. The problem with option 1 is that
different SASL mechanisms can have very different properties. You might want
to allow "NTLM" from a trusted network, but require "OTP" from the public
internet, for example. So I don't think a single GUC would be flexible
enough.That said, a GUC with a more narrow scope might be OK. If we called the
method in pg_hba.conf "secure_password", and had a GUC to list which
password-based mechanisms are considered secure, that would be OK. But I
think we'd still need a separate pg_hba.conf method name for OAUTHBEARER,
for example.Michael replied to my message with the idea to use a mechanism= HBA option.
That's better than a GUC.PS. If we go with the full names, I think it should "scram-sha-256", rather
than "scram_sha_256", because the official name uses dashes rather than
underscores.Agreed, I don't remember why I wrote underscores. One could argue on that
basis for using uppercase, but I won't.These are the two chief approaches I'm seeing:
1. scram-sha-256, scram-sha-256-plus, and successors will be their own
pg_hba.conf authentication methods. Until and unless someone implements an
ability to name multiple methods per HBA line, you must choose exactly one
SASL method. The concrete work for v10 would be merely renaming "scram" to
"scram-sha-256".2. Create a multiplexed authentication method like "sasl" or "scram" (not to
be confused with today's "scram" method, which denotes SCRAM-SHA-256
precisely). The DBA permits concrete methods like scram-sha-256 via HBA
option. Absent that option, the system could default to a reasonable list.I had been favoring (2), but I'm starting to like (1) more. (2) assumes all
SASL methods or all SCRAM methods have something in common with each other and
not with other methods, and that's not so. For example, one might implement
simultaneous md5 and scram-sha-256. (1) is harder to implement, but we can
defer that work indefinitely.
One thing to consider is that we just made the decision that "md5"
actually means "md5 or scram-sha-256". Extrapolating from that, I think
we'll want "scram-sha-256" to mean "scram-sha-256 or scram-sha-256-plus"
(i.e. the channel-bonding variant) in the future. And if we get support
for scram-sha-512, "scram-sha-256" would presumably allow that too.
Given that, we don't necessarily even need to support a list of methods,
if we always implicitly also allow anything stronger than what's
specified. At least until someone implements something completely
different like OAUTHBEARER, that's not clearly stronger or weaker than
the other methods.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 4/9/17 19:19, Noah Misch wrote:
These are the two chief approaches I'm seeing:
1. scram-sha-256, scram-sha-256-plus, and successors will be their own
pg_hba.conf authentication methods. Until and unless someone implements an
ability to name multiple methods per HBA line, you must choose exactly one
SASL method. The concrete work for v10 would be merely renaming "scram" to
"scram-sha-256".
I like that.
2. Create a multiplexed authentication method like "sasl" or "scram" (not to
be confused with today's "scram" method, which denotes SCRAM-SHA-256
precisely). The DBA permits concrete methods like scram-sha-256 via HBA
option. Absent that option, the system could default to a reasonable list.
The problem with that approach is that you would then eventually need
yet another place like pg_hba.conf to configure which SASL mechanisms to
use under which circumstances. pg_hba.conf is already that place for
the Legacy Authentication and Security Layer, so it could be that place
for SASL as well.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 4/10/17 04:27, Heikki Linnakangas wrote:
One thing to consider is that we just made the decision that "md5"
actually means "md5 or scram-sha-256". Extrapolating from that, I think
we'll want "scram-sha-256" to mean "scram-sha-256 or scram-sha-256-plus"
(i.e. the channel-bonding variant) in the future. And if we get support
for scram-sha-512, "scram-sha-256" would presumably allow that too.
But how would you choose between scram-sha-256-plus and scram-sha-512?
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/11/2017 04:52 AM, Peter Eisentraut wrote:
On 4/10/17 04:27, Heikki Linnakangas wrote:
One thing to consider is that we just made the decision that "md5"
actually means "md5 or scram-sha-256". Extrapolating from that, I think
we'll want "scram-sha-256" to mean "scram-sha-256 or scram-sha-256-plus"
(i.e. the channel-bonding variant) in the future. And if we get support
for scram-sha-512, "scram-sha-256" would presumably allow that too.But how would you choose between scram-sha-256-plus and scram-sha-512?
Good question. We would need to decide the order of preference for those.
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or
something. Secondly, the user's pg_authid row will contain a
SCRAM-SHA-256 or SCRAM-SHA-512 verifier, not both, so that will dictate
which one to use.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Apr 11, 2017 at 08:10:23AM +0300, Heikki Linnakangas wrote:
On 04/11/2017 04:52 AM, Peter Eisentraut wrote:
Good question. We would need to decide the order of preference for those.That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or something.
Secondly, the user's pg_authid row will contain a SCRAM-SHA-256 or
SCRAM-SHA-512 verifier, not both, so that will dictate which one to use.
It seems openssl has had to deal with cipher preferences for years and
invented ssl_ciphers.
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ As you are, so once was I. As I am, so you will be. +
+ Ancient Roman grave inscription +
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Apr 11, 2017 at 08:10:23AM +0300, Heikki Linnakangas wrote:
On 04/11/2017 04:52 AM, Peter Eisentraut wrote:
On 4/10/17 04:27, Heikki Linnakangas wrote:
One thing to consider is that we just made the decision that "md5"
actually means "md5 or scram-sha-256". Extrapolating from that, I think
we'll want "scram-sha-256" to mean "scram-sha-256 or scram-sha-256-plus"
(i.e. the channel-bonding variant) in the future. And if we get support
for scram-sha-512, "scram-sha-256" would presumably allow that too.But how would you choose between scram-sha-256-plus and scram-sha-512?
Good question. We would need to decide the order of preference for those.
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or something.
Secondly, the user's pg_authid row will contain a SCRAM-SHA-256 or
SCRAM-SHA-512 verifier, not both, so that will dictate which one to use.
[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item. Heikki,
since you committed the patch believed to have created it, you own this open
item. If some other commit is more relevant or if this does not belong as a
v10 open item, please let us know. Otherwise, please observe the policy on
open item ownership[1]/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com and send a status update within three calendar days of
this message. Include a date for your subsequent status update. Testers may
discover new open items at any time, and I want to plan to get them all fixed
well in advance of shipping v10. Consequently, I will appreciate your efforts
toward speedy resolution. Thanks.
[1]: /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 4/11/17 01:10, Heikki Linnakangas wrote:
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or
something. Secondly, the user's pg_authid row will contain a
SCRAM-SHA-256 or SCRAM-SHA-512 verifier, not both, so that will dictate
which one to use.
Right. So putting the actual password method in pg_hba.conf isn't going
to be useful very often.
I think the most practical thing that the user wants in pg_hba.conf is
"best password method supported by what is in pg_authid". This is
currently spelled "md5", which is of course pretty weird. And it will
become weirder over time.
I think we want to have a new keyword in pg_hba.conf for that, one which
does not indicate any particular algorithm or method (so not "scram" or
"sasl").
We could use "password". If we think that "md5" can mean md5-or-beyond,
then maybe "password" can mean password-or-md5-or-beyond.
Or otherwise a completely new word.
We also want to give users/admins a way to phase out old methods or set
some policy. We could either make a global GUC setting
password_methods='md5 scram-sha-256' and/or make that an option in
pg_hba.conf past the method field.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Apr 12, 2017 at 02:33:27AM -0400, Noah Misch wrote:
On Tue, Apr 11, 2017 at 08:10:23AM +0300, Heikki Linnakangas wrote:
On 04/11/2017 04:52 AM, Peter Eisentraut wrote:
On 4/10/17 04:27, Heikki Linnakangas wrote:
One thing to consider is that we just made the decision that "md5"
actually means "md5 or scram-sha-256". Extrapolating from that, I think
we'll want "scram-sha-256" to mean "scram-sha-256 or scram-sha-256-plus"
(i.e. the channel-bonding variant) in the future. And if we get support
for scram-sha-512, "scram-sha-256" would presumably allow that too.But how would you choose between scram-sha-256-plus and scram-sha-512?
Good question. We would need to decide the order of preference for those.
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or something.
Secondly, the user's pg_authid row will contain a SCRAM-SHA-256 or
SCRAM-SHA-512 verifier, not both, so that will dictate which one to use.[Action required within three days. This is a generic notification.]
The above-described topic is currently a PostgreSQL 10 open item. Heikki,
since you committed the patch believed to have created it, you own this open
item. If some other commit is more relevant or if this does not belong as a
v10 open item, please let us know. Otherwise, please observe the policy on
open item ownership[1] and send a status update within three calendar days of
this message. Include a date for your subsequent status update. Testers may
discover new open items at any time, and I want to plan to get them all fixed
well in advance of shipping v10. Consequently, I will appreciate your efforts
toward speedy resolution. Thanks.[1] /messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
This PostgreSQL 10 open item is past due for your status update. Kindly send
a status update within 24 hours, and include a date for your subsequent status
update. Refer to the policy on open item ownership:
/messages/by-id/20170404140717.GA2675809@tornado.leadboat.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 16 April 2017 07:14:21 EEST, Noah Misch <noah@leadboat.com> wrote:
This PostgreSQL 10 open item is past due for your status update.
Kindly send
a status update within 24 hours, and include a date for your subsequent
status
update.
I will pick this up on Tuesday. The consensus seems to be to change the option to "scram-sha-256", so I'll do that.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04/14/2017 10:33 PM, Peter Eisentraut wrote:
On 4/11/17 01:10, Heikki Linnakangas wrote:
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or
something. Secondly, the user's pg_authid row will contain a
SCRAM-SHA-256 or SCRAM-SHA-512 verifier, not both, so that will dictate
which one to use.Right. So putting the actual password method in pg_hba.conf isn't going
to be useful very often.I think the most practical thing that the user wants in pg_hba.conf is
"best password method supported by what is in pg_authid". This is
currently spelled "md5", which is of course pretty weird. And it will
become weirder over time.I think we want to have a new keyword in pg_hba.conf for that, one which
does not indicate any particular algorithm or method (so not "scram" or
"sasl").We could use "password". If we think that "md5" can mean md5-or-beyond,
then maybe "password" can mean password-or-md5-or-beyond.Or otherwise a completely new word.
We also want to give users/admins a way to phase out old methods or set
some policy. We could either make a global GUC setting
password_methods='md5 scram-sha-256' and/or make that an option in
pg_hba.conf past the method field.
Yeah, that would be reasonable. It can't be called just "password",
though, because there's no way to implement "password-or-md5-or-scram"
in a sensible way (see my reply to Simon at [1]/messages/by-id/fa6cec54-4fa9-756d-53be-a5ba3d03d881@iki.fi). Unless we remove the
support for what "password" does today altogether, and redefine
"password" to mean just "md5-or-beyond". Which might not be a bad idea,
but that's a separate discussion.
In any case, I think we would probably still need more fine-grained
control, too, so we would still need to have "scram-sha-256" as a method
you can specify directly in pg_hba.conf. So I consider this as a
separate, new, feature that we can add in the future, if it seems worth
the effort.
I've committed a simple renaming of "scram" to "scram-sha-256", as the
pg_hba.conf and password_encryption option. I think that will do for v10.
[1]: /messages/by-id/fa6cec54-4fa9-756d-53be-a5ba3d03d881@iki.fi
/messages/by-id/fa6cec54-4fa9-756d-53be-a5ba3d03d881@iki.fi
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Apr 18, 2017 at 1:52 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 04/14/2017 10:33 PM, Peter Eisentraut wrote:
On 4/11/17 01:10, Heikki Linnakangas wrote:
That question won't arise in practice. Firstly, if the server can do
scram-sha-256-plus, it presumably can also do scram-sha-512-plus. Unless
there's a change in the way the channel binding works, such that the
scram-sha-512-plus variant needs a newer version of OpenSSL or
something. Secondly, the user's pg_authid row will contain a
SCRAM-SHA-256 or SCRAM-SHA-512 verifier, not both, so that will dictate
which one to use.Right. So putting the actual password method in pg_hba.conf isn't going
to be useful very often.I think the most practical thing that the user wants in pg_hba.conf is
"best password method supported by what is in pg_authid". This is
currently spelled "md5", which is of course pretty weird. And it will
become weirder over time.I think we want to have a new keyword in pg_hba.conf for that, one which
does not indicate any particular algorithm or method (so not "scram" or
"sasl").We could use "password". If we think that "md5" can mean md5-or-beyond,
then maybe "password" can mean password-or-md5-or-beyond.Or otherwise a completely new word.
We also want to give users/admins a way to phase out old methods or set
some policy. We could either make a global GUC setting
password_methods='md5 scram-sha-256' and/or make that an option in
pg_hba.conf past the method field.Yeah, that would be reasonable. It can't be called just "password",
though, because there's no way to implement "password-or-md5-or-scram" in a
sensible way (see my reply to Simon at [1]). Unless we remove the support
for what "password" does today altogether, and redefine "password" to mean
just "md5-or-beyond". Which might not be a bad idea, but that's a separate
discussion.
It is an interesting one though. "password" today is really only useful in
the case of db_user_namespace=on, right? Given the very few people I think
are using that feature, it wouldn't be unreasonable to rename it to
something more closely related to that.
However, that would also leave us in the position to explain "before 10,
avoid using password because it stores in clear text. after 10, we
recommend you use password". Reusing something that's existed before and
not really been secure for something that would be a good choice in the
future seems like a bad idea.
But we can also implement this functionality but under a differet name.
Like just "hashed" or something, which would mean md5-or-scram?
In any case, I think we would probably still need more fine-grained
control, too, so we would still need to have "scram-sha-256" as a method
you can specify directly in pg_hba.conf. So I consider this as a separate,
new, feature that we can add in the future, if it seems worth the effort.
Yes, I think wherever we go we don't want to loose the fine-grained
control. But some people will be happier for not having to use it.
--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/>
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/>
On Tue, Apr 18, 2017 at 7:58 AM, Magnus Hagander <magnus@hagander.net> wrote:
Yeah, that would be reasonable. It can't be called just "password",
though, because there's no way to implement "password-or-md5-or-scram" in a
sensible way (see my reply to Simon at [1]). Unless we remove the support
for what "password" does today altogether, and redefine "password" to mean
just "md5-or-beyond". Which might not be a bad idea, but that's a separate
discussion.It is an interesting one though. "password" today is really only useful in
the case of db_user_namespace=on, right? Given the very few people I think
are using that feature, it wouldn't be unreasonable to rename it to
something more closely related to that.
I think it would be nice to have something with the same functionality
as db_user_namespace that smells less like a giant hack.
Does db_user_namespace work with SCRAM?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 05/02/2017 09:57 PM, Robert Haas wrote:
Does db_user_namespace work with SCRAM?
Yes. Haven't tested it, come to think of it, but it should work.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers