Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1p5PtG-0006Cb-0I for pgsql-hackers@arkaria.postgresql.org; Wed, 14 Dec 2022 11:25:34 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1p5PtE-0002Vd-St for pgsql-hackers@arkaria.postgresql.org; Wed, 14 Dec 2022 11:25:32 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1p5PtE-0002Uw-BK for pgsql-hackers@lists.postgresql.org; Wed, 14 Dec 2022 11:25:32 +0000 Received: from smtp.outgoing.loopia.se ([93.188.3.37]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1p5Pt9-00045A-Kk for pgsql-hackers@lists.postgresql.org; Wed, 14 Dec 2022 11:25:31 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id 41C562F75477 for ; Wed, 14 Dec 2022 12:25:24 +0100 (CET) Received: from s981.loopia.se (unknown [172.22.191.5]) by s807.loopia.se (Postfix) with ESMTP id 3108E2E28081; Wed, 14 Dec 2022 12:25:24 +0100 (CET) Received: from s475.loopia.se (unknown [172.22.191.6]) by s981.loopia.se (Postfix) with ESMTP id 2760222B175D; Wed, 14 Dec 2022 12:25:24 +0100 (CET) X-Virus-Scanned: amavisd-new at amavis.loopia.se X-Spam-Flag: NO X-Spam-Score: -1 X-Spam-Level: X-Spam-Status: No, score=-1 tagged_above=-999 required=6.2 tests=[ALL_TRUSTED=-1] autolearn=disabled Received: from s979.loopia.se ([172.22.191.6]) by s475.loopia.se (s475.loopia.se [172.22.190.15]) (amavisd-new, port 10024) with LMTP id xNDiCHf2bgzs; Wed, 14 Dec 2022 12:25:20 +0100 (CET) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 89.255.232.193 Received: from smtpclient.apple (customer-89-255-232-193.stosn.net [89.255.232.193]) (Authenticated sender: daniel@yesql.se) by s979.loopia.se (Postfix) with ESMTPSA id 1D88D10BC462; Wed, 14 Dec 2022 12:25:20 +0100 (CET) From: Daniel Gustafsson Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_2131242C-57E0-475B-8BA7-3ECAAF70EF1C" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.100.31\)) Subject: Re: Raising the SCRAM iteration count Date: Wed, 14 Dec 2022 12:25:19 +0100 In-Reply-To: Cc: "Jonathan S. Katz" , Andres Freund , PostgreSQL Hackers To: Michael Paquier References: <20221210001538.czikyvk3xtkphxfu@awork3.anarazel.de> <4880738a-cbf7-c9a1-4faf-ba861c731c63@postgresql.org> <75619A47-4CD0-4E0F-8A30-32F83FF593DD@yesql.se> X-Mailer: Apple Mail (2.3696.100.31) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_2131242C-57E0-475B-8BA7-3ECAAF70EF1C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 14 Dec 2022, at 02:00, Michael Paquier wrote: >=20 > On Tue, Dec 13, 2022 at 12:17:58PM +0100, Daniel Gustafsson wrote: >> It does raise an interesting point though, if we in the future add = suppprt for >> SCRAM-SHA-512 (which seems reasonable to do) it's not good enough to = have a >> single GUC for SCRAM iterations; we'd need to be able to set the = iteration >> count per algorithm. I'll account for that when updating the patch = downthread. >=20 > So, you mean that the GUC should be named like password_iterations, > taking a grammar with a list like 'scram-sha-256=3D4096,algo2=3D5000'? I was thinking about it but opted for the simpler approach of a GUC name = with the algorithm baked into it: scram_sha256_iterations. It doesn't seem = all that likely that we'll have more than two versions of SCRAM (sha256/sha512) = so the additional complexity doesn't seem worth it. The attached v2 has the GUC rename and a change to GUC_REPORT such that = the frontend can use the real value rather than the default. I kept it for = super users so far, do you think it should be a user setting being somewhat = sensitive?=20 The default in this version is rolled back to 4096 as there was pushback against raising it, and the lower limit is one in order to potentially = assist situations like the one Andres mentioned where md5 is used. -- Daniel Gustafsson https://vmware.com/ --Apple-Mail=_2131242C-57E0-475B-8BA7-3ECAAF70EF1C Content-Disposition: attachment; filename=v2-0001-Make-SCRAM-iteration-count-configurable.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-Make-SCRAM-iteration-count-configurable.patch" Content-Transfer-Encoding: quoted-printable =46rom=207187bfd83067f277e3658367a895fc6ac5aa53b0=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20= =0ADate:=20Wed,=2014=20Dec=202022=2011:52:36=20= +0100=0ASubject:=20[PATCH=20v2]=20Make=20SCRAM=20iteration=20count=20= configurable=0A=0AReplace=20the=20hardcoded=20value=20with=20a=20GUC=20= such=20that=20the=20iteration=20count=0Acan=20be=20raised=20in=20order=20= to=20increase=20protection=20against=20brute-force=0Aattacks.=20=20The=20= hardcoded=20value=20for=20SCRAM=20iteration=20count=20was=20defined=0Ato=20= be=204096,=20which=20is=20taken=20from=20RFC=207677,=20so=20set=20the=20= default=20for=20the=0AGUC=20to=204096=20to=20match.=20=20Raising=20the=20= iteration=20count=20will=20make=20stored=0Apasswords=20more=20resilient=20= to=20brute-force=20attacks=20at=20the=20cost=20of=20more=0Acomputation=20= performed=20during=20connection=20establishment.=20Lowering=20the=0A= count=20will=20reduce=20computational=20overhead=20during=20connections=20= at=20the=0Atradeoff=20of=20reducing=20strength=20against=20brute-force=20= attacks.=20When=20the=0Aalternative=20is=20to=20fall=20back=20to=20md5=20= instead,=20SCRAM=20with=20a=20very=20low=0Aiteration=20count=20is=20= still=20preferrable=20so=20allow=20iteration=20counts=20all=0Athe=20way=20= down=20to=20one.=0A=0AReviewed-by:=20Michael=20Paquier=20= =0ADiscussion:=20= https://postgr.es/m/F72E7BC7-189F-4B17-BF47-9735EB72C364@yesql.se=0A---=0A= =20doc/src/sgml/config.sgml=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=2020=20+++++++++++++++++++=0A=20= src/backend/libpq/auth-scram.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=209=20+++++++--=0A=20src/backend/utils/misc/guc_tables.c=20=20=20= =20=20=20=20=20=20=20=20|=2012=20+++++++++++=0A=20= src/backend/utils/misc/postgresql.conf.sample=20|=20=201=20+=0A=20= src/common/scram-common.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=203=20+--=0A=20src/include/common/scram-common.h=20=20= =20=20=20=20=20=20=20=20=20=20=20|=2010=20++++++++--=0A=20= src/interfaces/libpq/fe-auth-scram.c=20=20=20=20=20=20=20=20=20=20|=20=20= 4=20++--=0A=20src/interfaces/libpq/fe-auth.c=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=202=20+-=0A=20src/interfaces/libpq/fe-auth.h=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=201=20+=0A=20= src/interfaces/libpq/fe-connect.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=202=20++=0A=20src/interfaces/libpq/fe-exec.c=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=204=20++++=0A=20= src/interfaces/libpq/libpq-int.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=201=20+=0A=20src/test/authentication/t/001_password.pl=20=20=20=20=20= |=2016=20+++++++++++++++=0A=20src/test/regress/expected/password.out=20=20= =20=20=20=20=20=20|=2011=20+++++++---=0A=20= src/test/regress/sql/password.sql=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=205=20+++++=0A=2015=20files=20changed,=2089=20insertions(+),=2012=20= deletions(-)=0A=0Adiff=20--git=20a/doc/src/sgml/config.sgml=20= b/doc/src/sgml/config.sgml=0Aindex=208e4145979d..3da29e5a51=20100644=0A= ---=20a/doc/src/sgml/config.sgml=0A+++=20b/doc/src/sgml/config.sgml=0A@@=20= -1098,6=20+1098,26=20@@=20include_dir=20'conf.d'=0A=20=20=20=20=20=20=20= =0A=20=20=20=20=20=20=0A=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20= scram_sha256_iterations=20= (integer)=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20scram_sha256_iterations=20= configuration=20parameter=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20The=20number=20of=20= computational=20iterations=20to=20be=20performed=20when=20generating=0A+=20= =20=20=20=20=20=20=20a=20SCRAM-SHA-256=20password.=20The=20default=20is=20= 4096.=20A=0A+=20=20=20=20=20=20=20=20higher=20number=20= of=20iterations=20will=20provide=20additional=20protection=20against=0A+=20= =20=20=20=20=20=20=20brute-force=20attacks=20on=20stored=20passwords=20= but=20will=20make=20authentication=0A+=20=20=20=20=20=20=20=20slower.=20= Changing=20the=20value=20has=20no=20effect=20on=20already=20created=20= secrets,=0A+=20=20=20=20=20=20=20=20since=20the=20iteration=20count=20at=20= the=20time=20of=20creation=20is=20fixed=20for=20the=0A+=20=20=20=20=20=20= =20=20secret.=20In=20order=20to=20make=20use=20of=20a=20changed=20value=20= the=20password=20must=20be=0A+=20=20=20=20=20=20=20=20altered.=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=0A=20=20=20=20=20=20=0A=20=20= =20=20=20=20=20krb_server_keyfile=20= (string)=0A=20=20=20=20=20=20=20=0Adiff=20--git=20= a/src/backend/libpq/auth-scram.c=20b/src/backend/libpq/auth-scram.c=0A= index=20ee7f52218a..4bf377b189=20100644=0A---=20= a/src/backend/libpq/auth-scram.c=0A+++=20= b/src/backend/libpq/auth-scram.c=0A@@=20-184,6=20+184,11=20@@=20static=20= char=20*sanitize_char(char=20c);=0A=20static=20char=20= *sanitize_str(const=20char=20*s);=0A=20static=20char=20= *scram_mock_salt(const=20char=20*username);=0A=20=0A+/*=0A+=20*=20The=20= number=20of=20iterations=20to=20use=20when=20generating=20new=20secrets.=0A= +=20*/=0A+int=09=09=09scram_sha256_iterations;=0A+=0A=20/*=0A=20=20*=20= Get=20a=20list=20of=20SASL=20mechanisms=20that=20this=20module=20= supports.=0A=20=20*=0A@@=20-483,7=20+488,7=20@@=20= pg_be_scram_build_secret(const=20char=20*password)=0A=20=09=09=09=09=20= errmsg("could=20not=20generate=20random=20salt")));=0A=20=0A=20=09result=20= =3D=20scram_build_secret(saltbuf,=20SCRAM_DEFAULT_SALT_LEN,=0A-=09=09=09=09= =09=09=09=09SCRAM_DEFAULT_ITERATIONS,=20password,=0A+=09=09=09=09=09=09=09= =09scram_sha256_iterations,=20password,=0A=20=09=09=09=09=09=09=09=09= &errstr);=0A=20=0A=20=09if=20(prep_password)=0A@@=20-692,7=20+697,7=20@@=20= mock_scram_secret(const=20char=20*username,=20int=20*iterations,=20char=20= **salt,=0A=20=09encoded_salt[encoded_len]=20=3D=20'\0';=0A=20=0A=20=09= *salt=20=3D=20encoded_salt;=0A-=09*iterations=20=3D=20= SCRAM_DEFAULT_ITERATIONS;=0A+=09*iterations=20=3D=20= scram_sha256_iterations;=0A=20=0A=20=09/*=20StoredKey=20and=20ServerKey=20= are=20not=20used=20in=20a=20doomed=20authentication=20*/=0A=20=09= memset(stored_key,=200,=20SCRAM_KEY_LEN);=0Adiff=20--git=20= a/src/backend/utils/misc/guc_tables.c=20= b/src/backend/utils/misc/guc_tables.c=0Aindex=201bf14eec66..9d6acc7fc5=20= 100644=0A---=20a/src/backend/utils/misc/guc_tables.c=0A+++=20= b/src/backend/utils/misc/guc_tables.c=0A@@=20-40,6=20+40,7=20@@=0A=20= #include=20"commands/trigger.h"=0A=20#include=20"commands/user.h"=0A=20= #include=20"commands/vacuum.h"=0A+#include=20"common/scram-common.h"=0A=20= #include=20"jit/jit.h"=0A=20#include=20"libpq/auth.h"=0A=20#include=20= "libpq/libpq.h"=0A@@=20-3423,6=20+3424,17=20@@=20struct=20config_int=20= ConfigureNamesInt[]=20=3D=0A=20=09=09NULL,=20NULL,=20NULL=0A=20=09},=0A=20= =0A+=09{=0A+=09=09{"scram_sha256_iterations",=20PGC_SUSET,=20= CONN_AUTH_AUTH,=0A+=09=09=09gettext_noop("Sets=20the=20iteration=20count=20= for=20SCRAM=20secret=20generation."),=0A+=09=09=09NULL,=0A+=09=09=09= GUC_REPORT=20|=20GUC_SUPERUSER_ONLY=0A+=09=09},=0A+=09=09= &scram_sha256_iterations,=0A+=09=094096,=201,=20INT_MAX,=0A+=09=09NULL,=20= NULL,=20NULL=0A+=09},=0A+=0A=20=09/*=20End-of-list=20marker=20*/=0A=20=09= {=0A=20=09=09{NULL,=200,=200,=20NULL,=20NULL},=20NULL,=200,=200,=200,=20= NULL,=20NULL,=20NULL=0Adiff=20--git=20= a/src/backend/utils/misc/postgresql.conf.sample=20= b/src/backend/utils/misc/postgresql.conf.sample=0Aindex=20= 043864597f..2b2b8ca86f=20100644=0A---=20= a/src/backend/utils/misc/postgresql.conf.sample=0A+++=20= b/src/backend/utils/misc/postgresql.conf.sample=0A@@=20-94,6=20+94,7=20= @@=0A=20=0A=20#authentication_timeout=20=3D=201min=09=09#=201s-600s=0A=20= #password_encryption=20=3D=20scram-sha-256=09#=20scram-sha-256=20or=20= md5=0A+#scram_sha256_iterations=20=3D=204096=0A=20#db_user_namespace=20=3D= =20off=0A=20=0A=20#=20GSSAPI=20using=20Kerberos=0Adiff=20--git=20= a/src/common/scram-common.c=20b/src/common/scram-common.c=0Aindex=20= 1268625929..2dc9679a4d=20100644=0A---=20a/src/common/scram-common.c=0A= +++=20b/src/common/scram-common.c=0A@@=20-206,8=20+206,7=20@@=20= scram_build_secret(const=20char=20*salt,=20int=20saltlen,=20int=20= iterations,=0A=20=09int=09=09=09encoded_server_len;=0A=20=09int=09=09=09= encoded_result;=0A=20=0A-=09if=20(iterations=20<=3D=200)=0A-=09=09= iterations=20=3D=20SCRAM_DEFAULT_ITERATIONS;=0A+=09Assert(iterations=20>=20= 0);=0A=20=0A=20=09/*=20Calculate=20StoredKey=20and=20ServerKey=20*/=0A=20= =09if=20(scram_SaltedPassword(password,=20salt,=20saltlen,=20iterations,=0A= diff=20--git=20a/src/include/common/scram-common.h=20= b/src/include/common/scram-common.h=0Aindex=204acf2a78ad..97c63a7f31=20= 100644=0A---=20a/src/include/common/scram-common.h=0A+++=20= b/src/include/common/scram-common.h=0A@@=20-38,11=20+38,17=20@@=0A=20= #define=20SCRAM_DEFAULT_SALT_LEN=09=0916=0A=20=0A=20/*=0A-=20*=20Default=20= number=20of=20iterations=20when=20generating=20secret.=20=20Should=20be=20= at=20least=0A-=20*=204096=20per=20RFC=207677.=0A+=20*=20Default=20number=20= of=20iterations=20when=20generating=20secret.=0A=20=20*/=0A=20#define=20= SCRAM_DEFAULT_ITERATIONS=094096=0A=20=0A+#ifndef=20FRONTEND=0A+/*=0A+=20= *=20Number=20of=20iterations=20when=20generating=20new=20secrets.=0A+=20= */=0A+extern=20PGDLLIMPORT=20int=20scram_sha256_iterations;=0A+#endif=0A= +=0A=20extern=20int=09scram_SaltedPassword(const=20char=20*password,=20= const=20char=20*salt,=0A=20=09=09=09=09=09=09=09=09=20int=20saltlen,=20= int=20iterations,=20uint8=20*result,=0A=20=09=09=09=09=09=09=09=09=20= const=20char=20**errstr);=0Adiff=20--git=20= a/src/interfaces/libpq/fe-auth-scram.c=20= b/src/interfaces/libpq/fe-auth-scram.c=0Aindex=20c500bea9e7..cf5e8824d3=20= 100644=0A---=20a/src/interfaces/libpq/fe-auth-scram.c=0A+++=20= b/src/interfaces/libpq/fe-auth-scram.c=0A@@=20-882,7=20+882,7=20@@=20= verify_server_signature(fe_scram_state=20*state,=20bool=20*match,=0A=20=20= *=20error=20details.=0A=20=20*/=0A=20char=20*=0A= -pg_fe_scram_build_secret(const=20char=20*password,=20const=20char=20= **errstr)=0A+pg_fe_scram_build_secret(const=20char=20*password,=20int=20= iterations,=20const=20char=20**errstr)=0A=20{=0A=20=09char=09=20=20=20= *prep_password;=0A=20=09pg_saslprep_rc=20rc;=0A@@=20-913,7=20+913,7=20@@=20= pg_fe_scram_build_secret(const=20char=20*password,=20const=20char=20= **errstr)=0A=20=09}=0A=20=0A=20=09result=20=3D=20= scram_build_secret(saltbuf,=20SCRAM_DEFAULT_SALT_LEN,=0A-=09=09=09=09=09=09= =09=09SCRAM_DEFAULT_ITERATIONS,=20password,=0A+=09=09=09=09=09=09=09=09= iterations,=20password,=0A=20=09=09=09=09=09=09=09=09errstr);=0A=20=0A=20= =09free(prep_password);=0Adiff=20--git=20= a/src/interfaces/libpq/fe-auth.c=20b/src/interfaces/libpq/fe-auth.c=0A= index=204a6c358bb6..52fee8e579=20100644=0A---=20= a/src/interfaces/libpq/fe-auth.c=0A+++=20= b/src/interfaces/libpq/fe-auth.c=0A@@=20-1253,7=20+1253,7=20@@=20= PQencryptPasswordConn(PGconn=20*conn,=20const=20char=20*passwd,=20const=20= char=20*user,=0A=20=09{=0A=20=09=09const=20char=20*errstr=20=3D=20NULL;=0A= =20=0A-=09=09crypt_pwd=20=3D=20pg_fe_scram_build_secret(passwd,=20= &errstr);=0A+=09=09crypt_pwd=20=3D=20pg_fe_scram_build_secret(passwd,=20= conn->scram_iterations,=20&errstr);=0A=20=09=09if=20(!crypt_pwd)=0A=20=09= =09=09libpq_append_conn_error(conn,=20"could=20not=20encrypt=20password:=20= %s",=20errstr);=0A=20=09}=0Adiff=20--git=20= a/src/interfaces/libpq/fe-auth.h=20b/src/interfaces/libpq/fe-auth.h=0A= index=20049a8bb1a1..e41423a593=20100644=0A---=20= a/src/interfaces/libpq/fe-auth.h=0A+++=20= b/src/interfaces/libpq/fe-auth.h=0A@@=20-26,6=20+26,7=20@@=20extern=20= char=20*pg_fe_getauthname(PQExpBuffer=20errorMessage);=0A=20/*=20= Mechanisms=20in=20fe-auth-scram.c=20*/=0A=20extern=20const=20= pg_fe_sasl_mech=20pg_scram_mech;=0A=20extern=20char=20= *pg_fe_scram_build_secret(const=20char=20*password,=0A+=09=09=09=09=09=09= =09=09=09=20=20int=20iterations,=0A=20=09=09=09=09=09=09=09=09=09=20=20= const=20char=20**errstr);=0A=20=0A=20#endif=09=09=09=09=09=09=09/*=20= FE_AUTH_H=20*/=0Adiff=20--git=20a/src/interfaces/libpq/fe-connect.c=20= b/src/interfaces/libpq/fe-connect.c=0Aindex=20f88d672c6c..1741248f73=20= 100644=0A---=20a/src/interfaces/libpq/fe-connect.c=0A+++=20= b/src/interfaces/libpq/fe-connect.c=0A@@=20-586,6=20+586,7=20@@=20= pqDropServerData(PGconn=20*conn)=0A=20=09conn->std_strings=20=3D=20= false;=0A=20=09conn->default_transaction_read_only=20=3D=20= PG_BOOL_UNKNOWN;=0A=20=09conn->in_hot_standby=20=3D=20PG_BOOL_UNKNOWN;=0A= +=09conn->scram_iterations=20=3D=20SCRAM_DEFAULT_ITERATIONS;=0A=20=09= conn->sversion=20=3D=200;=0A=20=0A=20=09/*=20Drop=20large-object=20= lookup=20data=20*/=0A@@=20-3909,6=20+3910,7=20@@=20makeEmptyPGconn(void)=0A= =20=09conn->std_strings=20=3D=20false;=09/*=20unless=20server=20says=20= differently=20*/=0A=20=09conn->default_transaction_read_only=20=3D=20= PG_BOOL_UNKNOWN;=0A=20=09conn->in_hot_standby=20=3D=20PG_BOOL_UNKNOWN;=0A= +=09conn->scram_iterations=20=3D=20SCRAM_DEFAULT_ITERATIONS;=0A=20=09= conn->verbosity=20=3D=20PQERRORS_DEFAULT;=0A=20=09conn->show_context=20=3D= =20PQSHOW_CONTEXT_ERRORS;=0A=20=09conn->sock=20=3D=20PGINVALID_SOCKET;=0A= diff=20--git=20a/src/interfaces/libpq/fe-exec.c=20= b/src/interfaces/libpq/fe-exec.c=0Aindex=20da229d632a..35d3afbf2a=20= 100644=0A---=20a/src/interfaces/libpq/fe-exec.c=0A+++=20= b/src/interfaces/libpq/fe-exec.c=0A@@=20-1181,6=20+1181,10=20@@=20= pqSaveParameterStatus(PGconn=20*conn,=20const=20char=20*name,=20const=20= char=20*value)=0A=20=09=09conn->in_hot_standby=20=3D=0A=20=09=09=09= (strcmp(value,=20"on")=20=3D=3D=200)=20?=20PG_BOOL_YES=20:=20PG_BOOL_NO;=0A= =20=09}=0A+=09else=20if=20(strcmp(name,=20"scram_sha256_iterations")=20= =3D=3D=200)=0A+=09{=0A+=09=09conn->scram_iterations=20=3D=20atoi(value);=0A= +=09}=0A=20}=0A=20=0A=20=0Adiff=20--git=20= a/src/interfaces/libpq/libpq-int.h=20b/src/interfaces/libpq/libpq-int.h=0A= index=20512762f999..652df5b6ca=20100644=0A---=20= a/src/interfaces/libpq/libpq-int.h=0A+++=20= b/src/interfaces/libpq/libpq-int.h=0A@@=20-515,6=20+515,7=20@@=20struct=20= pg_conn=0A=20=09/*=20Assorted=20state=20for=20SASL,=20SSL,=20GSS,=20etc=20= */=0A=20=09const=20pg_fe_sasl_mech=20*sasl;=0A=20=09void=09=20=20=20= *sasl_state;=0A+=09int=09=09=09scram_iterations;=0A=20=0A=20=09/*=20SSL=20= structures=20*/=0A=20=09bool=09=09ssl_in_use;=0Adiff=20--git=20= a/src/test/authentication/t/001_password.pl=20= b/src/test/authentication/t/001_password.pl=0Aindex=20= 42d3d4c79b..a684a93d6e=20100644=0A---=20= a/src/test/authentication/t/001_password.pl=0A+++=20= b/src/test/authentication/t/001_password.pl=0A@@=20-86,6=20+86,14=20@@=20= $node->safe_psql('postgres',=0A=20=09q{SET=20password_encryption=3D'md5';=20= CREATE=20ROLE=20"md5,role"=20LOGIN=20PASSWORD=20'pass';}=0A=20);=0A=20=0A= +#=20Create=20a=20role=20with=20a=20non-default=20iteration=20count=0A= +$node->safe_psql(=0A+=09'postgres',=0A+=09"SET=20= password_encryption=3D'scram-sha-256';=0A+=09=20SET=20= scram_sha256_iterations=3D100000;=0A+=09=20CREATE=20ROLE=20= scram_role_iter=20LOGIN=20PASSWORD=20'pass';"=0A+);=0A+=0A=20#=20Create=20= a=20database=20to=20test=20regular=20expression.=0A=20= $node->safe_psql('postgres',=20"CREATE=20database=20regex_testdb;");=0A=20= =0A@@=20-134,6=20+142,14=20@@=20test_conn(=0A=20=09log_like=20=3D>=20[=0A= =20=09=09qr/connection=20authenticated:=20identity=3D"scram_role"=20= method=3Dscram-sha-256/=0A=20=09]);=0A+test_conn(=0A+=09$node,=0A+=09= 'user=3Dscram_role_iter',=0A+=09'scram-sha-256',=0A+=090,=0A+=09log_like=20= =3D>=20[=0A+=09=09qr/connection=20authenticated:=20= identity=3D"scram_role_iter"=20method=3Dscram-sha-256/=0A+=09]);=0A=20= test_conn($node,=20'user=3Dmd5_role',=20'scram-sha-256',=202,=0A=20=09= log_unlike=20=3D>=20[qr/connection=20authenticated:/]);=0A=20=0Adiff=20= --git=20a/src/test/regress/expected/password.out=20= b/src/test/regress/expected/password.out=0Aindex=20= 7c84c9da33..1a3dad23e3=20100644=0A---=20= a/src/test/regress/expected/password.out=0A+++=20= b/src/test/regress/expected/password.out=0A@@=20-72,12=20+72,15=20@@=20= CREATE=20ROLE=20regress_passwd6=20PASSWORD=20'SCRAM-SHA-256$1234';=0A=20= CREATE=20ROLE=20regress_passwd7=20PASSWORD=20= 'md5012345678901234567890123456789zz';=0A=20--=20invalid=20length=0A=20= CREATE=20ROLE=20regress_passwd8=20PASSWORD=20= 'md501234567890123456789012345678901zz';=0A+--=20Increasing=20the=20= SCRAM=20iteration=20count=0A+SET=20scram_sha256_iterations=20=3D=20= 99999;=0A+CREATE=20ROLE=20regress_passwd9=20PASSWORD=20= 'raisediterationcount';=0A=20SELECT=20rolname,=20= regexp_replace(rolpassword,=20= '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=3D]+)\$([a-zA-Z0-9+=3D/]+):([a-zA-Z0= -9+/=3D]+)',=20'\1$\2:$:')=20as=20= rolpassword_masked=0A=20=20=20=20=20FROM=20pg_authid=0A=20=20=20=20=20= WHERE=20rolname=20LIKE=20'regress_passwd%'=0A=20=20=20=20=20ORDER=20BY=20= rolname,=20rolpassword;=0A-=20=20=20=20=20rolname=20=20=20=20=20|=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20rolpassword_masked=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=0A= ------------------+---------------------------------------------------=0A= +=20=20=20=20=20rolname=20=20=20=20=20|=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20rolpassword_masked=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=0A= +-----------------+----------------------------------------------------=0A= =20=20regress_passwd1=20|=20md5cd3578025fe2c3d7ed1b9a9b26238b70=0A=20=20= regress_passwd2=20|=20md5dfa155cadd5f4ad57860162f3fab9cdb=0A=20=20= regress_passwd3=20|=20SCRAM-SHA-256$4096:$:=0A= @@=20-86,7=20+89,8=20@@=20SELECT=20rolname,=20= regexp_replace(rolpassword,=20'(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+=0A=20=20= regress_passwd6=20|=20SCRAM-SHA-256$4096:$:=0A= =20=20regress_passwd7=20|=20= SCRAM-SHA-256$4096:$:=0A=20=20= regress_passwd8=20|=20SCRAM-SHA-256$4096:$:=0A= -(8=20rows)=0A+=20regress_passwd9=20|=20= SCRAM-SHA-256$99999:$:=0A+(9=20rows)=0A=20=0A= =20--=20An=20empty=20password=20is=20not=20allowed,=20in=20any=20form=0A=20= CREATE=20ROLE=20regress_passwd_empty=20PASSWORD=20'';=0A@@=20-129,6=20= +133,7=20@@=20DROP=20ROLE=20regress_passwd5;=0A=20DROP=20ROLE=20= regress_passwd6;=0A=20DROP=20ROLE=20regress_passwd7;=0A=20DROP=20ROLE=20= regress_passwd8;=0A+DROP=20ROLE=20regress_passwd9;=0A=20DROP=20ROLE=20= regress_passwd_empty;=0A=20DROP=20ROLE=20regress_passwd_sha_len0;=0A=20= DROP=20ROLE=20regress_passwd_sha_len1;=0Adiff=20--git=20= a/src/test/regress/sql/password.sql=20= b/src/test/regress/sql/password.sql=0Aindex=2098f49916e5..8276afec86=20= 100644=0A---=20a/src/test/regress/sql/password.sql=0A+++=20= b/src/test/regress/sql/password.sql=0A@@=20-63,6=20+63,10=20@@=20CREATE=20= ROLE=20regress_passwd7=20PASSWORD=20= 'md5012345678901234567890123456789zz';=0A=20--=20invalid=20length=0A=20= CREATE=20ROLE=20regress_passwd8=20PASSWORD=20= 'md501234567890123456789012345678901zz';=0A=20=0A+--=20Increasing=20the=20= SCRAM=20iteration=20count=0A+SET=20scram_sha256_iterations=20=3D=20= 99999;=0A+CREATE=20ROLE=20regress_passwd9=20PASSWORD=20= 'raisediterationcount';=0A+=0A=20SELECT=20rolname,=20= regexp_replace(rolpassword,=20= '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=3D]+)\$([a-zA-Z0-9+=3D/]+):([a-zA-Z0= -9+/=3D]+)',=20'\1$\2:$:')=20as=20= rolpassword_masked=0A=20=20=20=20=20FROM=20pg_authid=0A=20=20=20=20=20= WHERE=20rolname=20LIKE=20'regress_passwd%'=0A@@=20-97,6=20+101,7=20@@=20= DROP=20ROLE=20regress_passwd5;=0A=20DROP=20ROLE=20regress_passwd6;=0A=20= DROP=20ROLE=20regress_passwd7;=0A=20DROP=20ROLE=20regress_passwd8;=0A= +DROP=20ROLE=20regress_passwd9;=0A=20DROP=20ROLE=20regress_passwd_empty;=0A= =20DROP=20ROLE=20regress_passwd_sha_len0;=0A=20DROP=20ROLE=20= regress_passwd_sha_len1;=0A--=20=0A2.32.1=20(Apple=20Git-133)=0A=0A= --Apple-Mail=_2131242C-57E0-475B-8BA7-3ECAAF70EF1C--