Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w34xU-000sQU-2d for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 04:26:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w34xT-00GEZu-2B for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 04:26:07 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w34xS-00GEZm-2X for pgsql-hackers@lists.postgresql.org; Thu, 19 Mar 2026 04:26:07 +0000 Received: from fhigh-a6-smtp.messagingengine.com ([103.168.172.157]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1w34xN-000000013lL-12Q3 for pgsql-hackers@lists.postgresql.org; Thu, 19 Mar 2026 04:26:06 +0000 Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfhigh.phl.internal (Postfix) with ESMTP id 534391400218; Thu, 19 Mar 2026 00:25:59 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Thu, 19 Mar 2026 00:25:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1773894359; x=1773980759; bh=PYtLANHEPx um6xcvABos7wdrJ2aB2CKx4lwB+CQ/nto=; b=vSPQGwacKonEGfhJmsF3SgfJby 8q2tE97PFcG5ibdk8JfUVT8R/gU3K68IAfjNNM7/WIP8vvQ/5C9AYIaPwl/HMQtn yZeMYZZvOpLusf2sDXY5i51iS+CcAgxlFQXSDLY8uEIKGbvncTZj5VZ1twgmnnLe ECW7tVoHBDWTDqnbde/8Ue4avsw6wx7um68H/gTRCBRqCv2pmDeMFqg3+KP+eZSx yuNsY97NDQWIXoOOTS7kyXGmHinOKvx0w3m1tspJhy9NLgyKTZOkiTY78f4Cq/kF zcJ9cFCGi8Vbyd7qzRUbxqnbK7+YKWYDoLoMNd6aXECjxshEuegoGvUR4GJQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1773894359; x=1773980759; bh=PYtLANHEPxum6xcvABos7wdrJ2aB2CKx4lw B+CQ/nto=; b=F3+rGkyv8qU+bEGhyMxxk2IwL79aCzhkqmB6UEJUXgReSYxsmem qlnwdFz8LWaUxksNLxfd2qAsu/SvIgHWrGeCeQND4Dnp6wuwu/uynHbEAED3FIhQ mVfO7Bbcl4R/qz2fQYeXLoqhbXzo+ynlEx4RZKODy7zAi5O2M6B0rGSkDJLSx+h4 IpC7gP5tqwxNkGxMnSUGEu2l6w9Fo3dqiLP3Tmknn/N76WorVeDvCZGNnnPKemFg wNJnRwjZjZ3XF/xDCRNn+OAOalPQqPotPVsao/+NNEzBcESxMHoJ3cQAwXkalUqY xeVdKNywbAVDMEr8Vov+CZhGREsOv2IWjVQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgdeftdeitdehucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnegfrh hlucfvnfffucdljedtmdenucfjughrpeffhffvvefukfhfgggtuggjsehgtderredttddv necuhfhrohhmpefoihgthhgrvghlucfrrghquhhivghruceomhhitghhrggvlhesphgrqh huihgvrhdrgiihiieqnecuggftrfgrthhtvghrnhepteelieefudffhffhtdetleeggeeg fffhkeeuveetiefgudduvedutefggeeivdejnecuvehluhhsthgvrhfuihiivgeptdenuc frrghrrghmpehmrghilhhfrhhomhepmhhitghhrggvlhesphgrqhhuihgvrhdrgiihiidp nhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepjhhohh hntghnrgihlhhorhhlshesghhmrghilhdrtghomhdprhgtphhtthhopehpghhsqhhlqdhh rggtkhgvrhhssehlihhsthhsrdhpohhsthhgrhgvshhqlhdrohhrgh X-ME-Proxy: Feedback-ID: i0fe9450f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 19 Mar 2026 00:25:57 -0400 (EDT) Date: Thu, 19 Mar 2026 13:25:52 +0900 From: Michael Paquier To: John Naylor Cc: Postgres hackers Subject: Re: Non-compliant SASLprep implementation for ASCII characters Message-ID: References: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="OWQ2F2onObjpvgt0" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --OWQ2F2onObjpvgt0 Content-Type: multipart/mixed; boundary="sjoVJoQrPjr5b6RX" Content-Disposition: inline --sjoVJoQrPjr5b6RX Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Mar 18, 2026 at 06:34:03PM +0700, John Naylor wrote: > Seems sensible to me. I only have minor nitpicks: Thanks for the review of the module. > +operation for a single byte as well as a range of these, acting as thin > +wrappers standing on top of pg_saslprep(). >=20 > It's more natural to say "wrappers around", at least that's what comes to= me. Fixed. > + if (unlikely(utf8_len =3D=3D 0)) >=20 > The exceptional path only has two lines of code, so it's unclear what > this hint is trying to do. This module isn't run by default anyway Removed that. > + MemSet(nulls, false, sizeof(nulls)); >=20 > Regular "memset" with a 4-byte constant input is easily inline-able by > the compiler, and I think we should use our homegrown implementation > only when there is a specific reason for it. (I know there are many > dozens of uses without a reason already, but...) Removed that. > -is($result, 'U+0000|SUCCESS|\x00|\x', "Only nul authorized for all > valid UTF8 codepoints"); > +is($result, '', "No empty or NULL values for all valid UTF8 codepoints"); >=20 > I don't quite understand "only nul authorized..." -- I understand the > explanation in your email, but I having difficulty with the way it's > phrased here. (Although it'll be moot if we go ahead with 0002) Yes, still better to keep the state of the tree cleaner at all times, especially if 0002 gets reverted. I have used a simpler "valid codepoints returning an empty password". Applied the result for the module, to have at least the coverage part. The last piece is refreshed, and attached for now. -- Michael --sjoVJoQrPjr5b6RX Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v3-0001-Make-implementation-of-SASLprep-compliant-for-ASC.patch Content-Transfer-Encoding: quoted-printable =46rom a806e48445ee7d9d75dbe70e0da76b703650faa4 Mon Sep 17 00:00:00 2001 =46rom: Michael Paquier Date: Thu, 19 Mar 2026 13:18:28 +0900 Subject: [PATCH v3] Make implementation of SASLprep compliant for ASCII characters --- src/common/saslprep.c | 12 ---- .../test_saslprep/expected/test_saslprep.out | 66 +++++++++---------- .../test_saslprep/t/001_saslprep_ranges.pl | 4 +- 3 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/common/saslprep.c b/src/common/saslprep.c index 2ad2cefc14fb..38d50dd823c4 100644 --- a/src/common/saslprep.c +++ b/src/common/saslprep.c @@ -1061,18 +1061,6 @@ pg_saslprep(const char *input, char **output) /* Ensure we return *output as NULL on failure */ *output =3D NULL; =20 - /* - * Quick check if the input is pure ASCII. An ASCII string requires no - * further processing. - */ - if (pg_is_ascii(input)) - { - *output =3D STRDUP(input); - if (!(*output)) - goto oom; - return SASLPREP_SUCCESS; - } - /* * Convert the input from UTF-8 to an array of Unicode codepoints. * diff --git a/src/test/modules/test_saslprep/expected/test_saslprep.out b/sr= c/test/modules/test_saslprep/expected/test_saslprep.out index f72dbffa0a11..92f93365343e 100644 --- a/src/test/modules/test_saslprep/expected/test_saslprep.out +++ b/src/test/modules/test_saslprep/expected/test_saslprep.out @@ -19,38 +19,38 @@ SELECT FROM generate_series(0,127) AS a; dat | byt | saslprep =20 ----------+------+------------------- - | \x00 | ("\\x",SUCCESS) - | \x01 | ("\\x01",SUCCESS) - | \x02 | ("\\x02",SUCCESS) - | \x03 | ("\\x03",SUCCESS) - | \x04 | ("\\x04",SUCCESS) - | \x05 | ("\\x05",SUCCESS) - | \x06 | ("\\x06",SUCCESS) - | \x07 | ("\\x07",SUCCESS) - | \x08 | ("\\x08",SUCCESS) - | \x09 | ("\\x09",SUCCESS) - | \x0a | ("\\x0a",SUCCESS) - | \x0b | ("\\x0b",SUCCESS) - | \x0c | ("\\x0c",SUCCESS) - | \x0d | ("\\x0d",SUCCESS) - | \x0e | ("\\x0e",SUCCESS) - | \x0f | ("\\x0f",SUCCESS) - | \x10 | ("\\x10",SUCCESS) - | \x11 | ("\\x11",SUCCESS) - | \x12 | ("\\x12",SUCCESS) - | \x13 | ("\\x13",SUCCESS) - | \x14 | ("\\x14",SUCCESS) - | \x15 | ("\\x15",SUCCESS) - | \x16 | ("\\x16",SUCCESS) - | \x17 | ("\\x17",SUCCESS) - | \x18 | ("\\x18",SUCCESS) - | \x19 | ("\\x19",SUCCESS) - | \x1a | ("\\x1a",SUCCESS) - | \x1b | ("\\x1b",SUCCESS) - | \x1c | ("\\x1c",SUCCESS) - | \x1d | ("\\x1d",SUCCESS) - | \x1e | ("\\x1e",SUCCESS) - | \x1f | ("\\x1f",SUCCESS) + | \x00 | (,PROHIBITED) + | \x01 | (,PROHIBITED) + | \x02 | (,PROHIBITED) + | \x03 | (,PROHIBITED) + | \x04 | (,PROHIBITED) + | \x05 | (,PROHIBITED) + | \x06 | (,PROHIBITED) + | \x07 | (,PROHIBITED) + | \x08 | (,PROHIBITED) + | \x09 | (,PROHIBITED) + | \x0a | (,PROHIBITED) + | \x0b | (,PROHIBITED) + | \x0c | (,PROHIBITED) + | \x0d | (,PROHIBITED) + | \x0e | (,PROHIBITED) + | \x0f | (,PROHIBITED) + | \x10 | (,PROHIBITED) + | \x11 | (,PROHIBITED) + | \x12 | (,PROHIBITED) + | \x13 | (,PROHIBITED) + | \x14 | (,PROHIBITED) + | \x15 | (,PROHIBITED) + | \x16 | (,PROHIBITED) + | \x17 | (,PROHIBITED) + | \x18 | (,PROHIBITED) + | \x19 | (,PROHIBITED) + | \x1a | (,PROHIBITED) + | \x1b | (,PROHIBITED) + | \x1c | (,PROHIBITED) + | \x1d | (,PROHIBITED) + | \x1e | (,PROHIBITED) + | \x1f | (,PROHIBITED) | \x20 | ("\\x20",SUCCESS) ! | \x21 | ("\\x21",SUCCESS) " | \x22 | ("\\x22",SUCCESS) @@ -146,7 +146,7 @@ SELECT | | \x7c | ("\\x7c",SUCCESS) } | \x7d | ("\\x7d",SUCCESS) ~ | \x7e | ("\\x7e",SUCCESS) - | \x7f | ("\\x7f",SUCCESS) + | \x7f | (,PROHIBITED) (128 rows) =20 DROP EXTENSION test_saslprep; diff --git a/src/test/modules/test_saslprep/t/001_saslprep_ranges.pl b/src/= test/modules/test_saslprep/t/001_saslprep_ranges.pl index b353017c0651..4a7cb5aaa588 100644 --- a/src/test/modules/test_saslprep/t/001_saslprep_ranges.pl +++ b/src/test/modules/test_saslprep/t/001_saslprep_ranges.pl @@ -25,14 +25,12 @@ $node->safe_psql('postgres', 'CREATE EXTENSION test_sas= lprep;'); # Among all the valid UTF-8 codepoint ranges, our implementation of # SASLprep should never return an empty password if the operation is # considered a success. -# The only exception is currently the nul character, prohibited in -# input of CREATE/ALTER ROLE. my $result =3D $node->safe_psql( 'postgres', qq[SELECT * FROM test_saslprep_ranges() WHERE status =3D 'SUCCESS' AND res IN (NULL, '') ]); =20 -is($result, 'U+0000|SUCCESS|\x00|\x', "valid codepoints returning an empty= password"); +is($result, '', "valid codepoints returning an empty password"); =20 $node->stop; done_testing(); --=20 2.53.0 --sjoVJoQrPjr5b6RX-- --OWQ2F2onObjpvgt0 Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmm7etAACgkQnvQgOdby QH1Y2Q/+J24sp8xlgIoECv8Ap1Oq12Wmh+pN2GSxAg8Na/Y1IccEeXya1iUE/Dev MTtc7EGBAJ/i+bHQScO4OOg1xCYZcpACP1jjMG90eb7segv+7+u3rgmLwjnz1kvC eCcqqoTnkHlmHmvJUagxMl2lHDJaRwL8bJAAwtLG15TJBrRJGLcCC4Q09ioZnEO4 YKa7QFjRcWxSGGGORtnbcqW0g87pTGz/qUL8DhvDbFakOZfL7W7bNbEBPV/TaYxe 2HAz1bzic/NLpt9oCOxFRqKe/Gun5aeDG5UuBQs/5HtC6t+Zub6SwKkFWK+BWzgw N5G9k4KHaOu31St0xnf0UKmbO9jnINepekm007aOhXvvHLs17KbH/Kp380SAcLs9 v5zVoUDw9fdtAqWE3ahuVy86f+0VfkF61GAh5OGZ2NhWFRnpcFRtysfkq9AhVzUa 5OyxL4F3QoKJrJZ8eTzYqJUvLlk+b+vTRww/VNCgqQuat3Q/EgbkRw0AVtNbGXaP t5+QNxb9cl/F0i60pQIqMDo2Cf7VTZeq/gZn3qM0h+mHfxPIKIzhF8KZE1adWqJE Oar19bJ+oNAnMy/xOai78+t0Ol6eH539G9OLgMjHtRhWEfJ0KgqG3BcrtP9SqiM5 kUrFgfb18CC4t7A2KzJVyOeunh+dxlnY2KWBQbHQMykInrXrYsE= =ZPNV -----END PGP SIGNATURE----- --OWQ2F2onObjpvgt0--