Re: Setting min/max TLS protocol in clientside libpq

Daniel Gustafsson <[email protected]> Tue, 14 Jan 2020 23:01:00 +0100
Newsgroups gmane.comp.db.postgresql.devel.general
Message-ID <[email protected]>
--Apple-Mail=_22F5B6EA-FF0D-46DC-9F32-D92CD5987730
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=utf-8

> On 14 Jan 2020, at 16:15, Daniel Gustafsson <[email protected]> wrote:
>=20
>> On 14 Jan 2020, at 15:49, Tom Lane <[email protected]> wrote:
>>=20
>> Daniel Gustafsson <[email protected]> writes:
>>>>> On 11 Jan 2020, at 03:49, Michael Paquier <[email protected]> =
wrote:
>>>>> One thing I noticed when looking at it is that we now have =
sha2_openssl.c and
>>>>> openssl_protocol.c in src/common.  For easier visual grouping of =
OpenSSL
>>>>> functionality, it makes sense to me to rename sha2_openssl.c to =
openssl_sha2.c,
>>>>> but that might just be pointless churn.
>>=20
>>>> Databases like consistency, and so do I, so no issues from me to do =
a
>>>> rename of the sha2.c file.  That makes sense with the addition of =
the
>>>> new file.
>>=20
>>> Done in the attached v3.
>>=20
>> I'm kind of down on renaming files unless there is a *really* strong
>> reason for it.  It makes back-patching more difficult and it makes
>> it much harder to follow the git history.  And, seeing that there is
>> also a src/common/sha2.c, it seems to me that renaming sha2_openssl.c
>> will just break consistency in a different way.
>>=20
>> Maybe the problem is you've got the new file's name backwards.
>> Maybe it should be protocol_openssl.c.
>=20
> Thats a very good argument, I=E2=80=99ll send a v4 with =
protocol_openssl.c when back at the computer.

Files renamed to match existing naming convention, the rest of the patch =
left
unchanged.

cheers ./daniel


--Apple-Mail=_22F5B6EA-FF0D-46DC-9F32-D92CD5987730
Content-Disposition: attachment;
	filename=libpq_minmaxproto_v4.patch
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="libpq_minmaxproto_v4.patch"
Content-Transfer-Encoding: quoted-printable

=46rom=20759709c69b6d9e75eb0597d4355fb5854ceb7b4b=20Mon=20Sep=2017=20=
00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20<[email protected]>=0A=
Date:=20Sat,=2030=20Nov=202019=2001:32:04=20+0100=0ASubject:=20[PATCH]=20=
Allow=20setting=20min/max=20TLS=20protocol=20version=20in=20libpq=0A=0A=
In=20the=20backend=20there=20are=20GUCs=20to=20control=20the=20minimum=20=
and=20maximum=20TLS=0Aversions=20to=20allow=20for=20a=20connection,=20=
but=20the=20clientside=20libpq=20lacked=0Athis=20ability.=20=20=
Disallowing=20servers=20which=20aren't=20providing=20secure=20TLS=0A=
protocols=20is=20of=20interest=20to=20clients,=20but=20we=20provide=20a=20=
maximum=20protocol=0Aversion=20setting=20by=20the=20same=20rationale=20=
as=20for=20the=20backend;=20to=20aid=20with=0Atesting=20and=20to=20cope=20=
with=20misbehaving=20software.=0A=0AThis=20refactors=20the=20OpenSSL=20=
replacement=20functions=20for=20setting=20TLS=0Aversion=20from=20the=20=
backend=20to=20src/common=20to=20avoid=20code=20duplication.=0A---=0A=20=
doc/src/sgml/libpq.sgml=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20|=20=2065=20+++++++++++++=0A=20src/backend/libpq/be-secure-openssl.c=20=
=20=20=20|=20=2099=20+------------------=0A=20src/common/Makefile=20=20=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/common/protocol_openssl.c=20=20=20=20=20=20=20=20=20=20=20=20=
|=20115=20+++++++++++++++++++++++=0A=20src/include/common/openssl.h=20=20=
=20=20=20=20=20=20=20=20=20=20=20|=20=2027=20++++++=0A=20=
src/interfaces/libpq/fe-connect.c=20=20=20=20=20=20=20=20|=20=20=208=20=
++=0A=20src/interfaces/libpq/fe-secure-openssl.c=20|=20=2081=20=
++++++++++++++++=0A=20src/interfaces/libpq/libpq-int.h=20=20=20=20=20=20=20=
=20=20|=20=20=202=20+=0A=20src/test/ssl/t/001_ssltests.pl=20=20=20=20=20=20=
=20=20=20=20=20|=20=2014=20++-=0A=20src/tools/msvc/Mkvcbuild.pm=20=20=20=20=
=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=2010=20files=20changed,=20=
315=20insertions(+),=20100=20deletions(-)=0A=20create=20mode=20100644=20=
src/common/protocol_openssl.c=0A=20create=20mode=20100644=20=
src/include/common/openssl.h=0A=0Adiff=20--git=20=
a/doc/src/sgml/libpq.sgml=20b/doc/src/sgml/libpq.sgml=0Aindex=20=
64cff49c4d..5c7816ce6f=20100644=0A---=20a/doc/src/sgml/libpq.sgml=0A+++=20=
b/doc/src/sgml/libpq.sgml=0A@@=20-1727,6=20+1727,33=20@@=20=
postgresql://%2Fvar%2Flib%2Fpostgresql/dbname=0A=20=20=20=20=20=20=20=
</listitem>=0A=20=20=20=20=20=20</varlistentry>=0A=20=0A+=20=20=20=20=20=
<varlistentry=20id=3D"libpq-connect-sslminprotocolversion"=20=
xreflabel=3D"sslminprotocolversion">=0A+=20=20=20=20=20=20=
<term><literal>sslminprotocolversion</literal></term>=0A+=20=20=20=20=20=20=
<listitem>=0A+=20=20=20=20=20=20=20<para>=0A+=20=20=20=20=20=20=20=20=
This=20parameter=20specifies=20the=20minimum=20SSL/TLS=20protocol=20=
version=20to=20allow=0A+=20=20=20=20=20=20=20=20for=20the=20connection.=20=
=20Valid=20values=20are=20<literal>TLSv1</literal>,=0A+=20=20=20=20=20=20=
=20=20<literal>TLSv1.1</literal>,=20<literal>TLSv1.2</literal>=20and=0A+=20=
=20=20=20=20=20=20=20<literal>TLSv1.3</literal>.=20=20The=20supported=20=
protocols=20depend=20on=20the=0A+=20=20=20=20=20=20=20=20version=20of=20=
<productname>OpenSSL</productname>=20used,=20older=20versions=0A+=20=20=20=
=20=20=20=20=20doesn't=20support=20the=20modern=20protocol=20versions.=0A=
+=20=20=20=20=20=20=20</para>=0A+=20=20=20=20=20=20</listitem>=0A+=20=20=20=
=20=20</varlistentry>=0A+=0A+=20=20=20=20=20<varlistentry=20=
id=3D"libpq-connect-sslmaxprotocolversion"=20=
xreflabel=3D"sslmaxprotocolversion">=0A+=20=20=20=20=20=20=
<term><literal>sslmaxprotocolversion</literal></term>=0A+=20=20=20=20=20=20=
<listitem>=0A+=20=20=20=20=20=20=20<para>=0A+=20=20=20=20=20=20=20=20=
This=20parameter=20specifies=20the=20maximum=20SSL/TLS=20protocol=20=
version=20to=20allow=0A+=20=20=20=20=20=20=20=20for=20the=20connection.=20=
The=20supported=20values=20are=20the=20same=20as=20for=20<literal>=0A+=20=
=20=20=20=20=20=20=20sslminprotocolversion</literal>.=20=20Setting=20a=20=
maximum=20protocol=20version=20is=0A+=20=20=20=20=20=20=20=20generally=20=
only=20useful=20for=20testing,=20or=20in=20case=20there=20are=20software=20=
components=0A+=20=20=20=20=20=20=20=20which=20doesn't=20support=20newer=20=
protocol=20versions.=0A+=20=20=20=20=20=20=20</para>=0A+=20=20=20=20=20=20=
</listitem>=0A+=20=20=20=20=20</varlistentry>=0A+=0A=20=20=20=20=20=20=
<varlistentry=20id=3D"libpq-connect-krbsrvname"=20=
xreflabel=3D"krbsrvname">=0A=20=20=20=20=20=20=20=
<term><literal>krbsrvname</literal></term>=0A=20=20=20=20=20=20=20=
<listitem>=0A@@=20-7115,6=20+7142,26=20@@=20myEventProc(PGEventId=20=
evtId,=20void=20*evtInfo,=20void=20*passThrough)=0A=20=20=20=20=20=20=
</para>=0A=20=20=20=20=20</listitem>=0A=20=0A+=20=20=20=20<listitem>=0A+=20=
=20=20=20=20<para>=0A+=20=20=20=20=20=20<indexterm>=0A+=20=20=20=20=20=20=
=20<primary><envar>PGSSLMINPROTOCOLVERSION</envar></primary>=0A+=20=20=20=
=20=20=20</indexterm>=0A+=20=20=20=20=20=20=
<envar>PGSSLMINPROTOCOLVERSION</envar>=20behaves=20the=20same=20as=20the=20=
<xref=0A+=20=20=20=20=20=20=
linkend=3D"libpq-connect-sslminprotocolversion"/>=20connection=20=
parameter.=0A+=20=20=20=20=20</para>=0A+=20=20=20=20</listitem>=0A+=0A+=20=
=20=20=20<listitem>=0A+=20=20=20=20=20<para>=0A+=20=20=20=20=20=20=
<indexterm>=0A+=20=20=20=20=20=20=20=
<primary><envar>PGSSLMAXPROTOCOLVERSION</envar></primary>=0A+=20=20=20=20=
=20=20</indexterm>=0A+=20=20=20=20=20=20=
<envar>PGSSLMAXPROTOCOLVERSION</envar>=20behaves=20the=20same=20as=20the=20=
<xref=0A+=20=20=20=20=20=20=
linkend=3D"libpq-connect-sslminprotocolversion"/>=20connection=20=
parameter.=0A+=20=20=20=20=20</para>=0A+=20=20=20=20</listitem>=0A+=0A=20=
=20=20=20=20<listitem>=0A=20=20=20=20=20=20<para>=0A=20=20=20=20=20=20=20=
<indexterm>=0A@@=20-7788,6=20+7835,24=20@@=20=
ldap://ldap.acme.com/cn=3Ddbserver,cn=3Dhosts?pgconnectinfo?base?(objectcl=
ass=3D*)=0A=20=0A=20=20</sect2>=0A=20=0A+=20<sect2>=0A+=20=20=
<title>Client=20Protocol=20Usage</title>=0A+=0A+=20=20<para>=0A+=20=20=20=
When=20connecting=20using=20SSL,=20the=20client=20and=20server=20=
negotiate=20which=20protocol=0A+=20=20=20to=20use=20for=20the=20=
connection.=20=20<productname>PostgreSQL</productname>=20supports=0A+=20=20=
=20<literal>TLSv1</literal>,=20<literal>TLSv1.1</literal>,=20=
<literal>TLSv1.2</literal>=0A+=20=20=20and=20<literal>TLSv1.3</literal>,=20=
but=20the=20protocols=20available=20depends=20on=20the=0A+=20=20=20=
version=20of=20<productname>OpenSSL</productname>=20which=20the=20client=20=
is=20using.=0A+=20=20=20The=20minimum=20requested=20version=20can=20be=20=
specified=20with=20<literal>sslminprotocolversion</literal>,=0A+=20=20=20=
which=20will=20ensure=20that=20the=20connection=20use=20that=20version,=20=
or=20higher,=20or=20fails.=0A+=20=20=20The=20maximum=20requested=20=
version=20can=20be=20specified=20with=20=
<literal>sslmaxprotocolversion</literal>,=0A+=20=20=20but=20this=20is=20=
mainly=20only=20useful=20for=20testing,=20or=20in=20case=20a=20component=20=
doesn't=0A+=20=20=20work=20with=20a=20newer=20protocol.=0A+=20=20</para>=0A=
+=20=20=20=0A+=20</sect2>=0A+=0A=20=20<sect2=20id=3D"libpq-ssl-fileusage">=
=0A=20=20=20<title>SSL=20Client=20File=20Usage</title>=0A=20=0Adiff=20=
--git=20a/src/backend/libpq/be-secure-openssl.c=20=
b/src/backend/libpq/be-secure-openssl.c=0Aindex=2062f1fcab2b..0cc59f1be1=20=
100644=0A---=20a/src/backend/libpq/be-secure-openssl.c=0A+++=20=
b/src/backend/libpq/be-secure-openssl.c=0A@@=20-36,6=20+36,7=20@@=0A=20=
#include=20<openssl/ec.h>=0A=20#endif=0A=20=0A+#include=20=
"common/openssl.h"=0A=20#include=20"libpq/libpq.h"=0A=20#include=20=
"miscadmin.h"=0A=20#include=20"pgstat.h"=0A@@=20-69,11=20+70,6=20@@=20=
static=20bool=20ssl_is_server_start;=0A=20=0A=20static=20int=09=
ssl_protocol_version_to_openssl(int=20v,=20const=20char=20*guc_name,=0A=20=
=09=09=09=09=09=09=09=09=09=09=09int=20loglevel);=0A-#ifndef=20=
SSL_CTX_set_min_proto_version=0A-static=20int=09=
SSL_CTX_set_min_proto_version(SSL_CTX=20*ctx,=20int=20version);=0A=
-static=20int=09SSL_CTX_set_max_proto_version(SSL_CTX=20*ctx,=20int=20=
version);=0A-#endif=0A-=0A=20=0A=20/*=20=
------------------------------------------------------------=20*/=0A=20=
/*=09=09=09=09=09=09=20Public=20interface=09=09=09=09=09=09*/=0A@@=20=
-1314,96=20+1310,3=20@@=20ssl_protocol_version_to_openssl(int=20v,=20=
const=20char=20*guc_name,=20int=20loglevel)=0A=20=09=09=09=09=09=
GetConfigOption(guc_name,=20false,=20false))));=0A=20=09return=20-1;=0A=20=
}=0A-=0A-/*=0A-=20*=20Replacements=20for=20APIs=20present=20in=20newer=20=
versions=20of=20OpenSSL=0A-=20*/=0A-#ifndef=20=
SSL_CTX_set_min_proto_version=0A-=0A-/*=0A-=20*=20OpenSSL=20versions=20=
that=20support=20TLS=201.3=20shouldn't=20get=20here=20because=20they=0A-=20=
*=20already=20have=20these=20functions.=20=20So=20we=20don't=20have=20to=20=
keep=20updating=20the=20below=0A-=20*=20code=20for=20every=20new=20TLS=20=
version,=20and=20eventually=20it=20can=20go=20away.=20=20But=20let's=0A-=20=
*=20just=20check=20this=20to=20make=20sure=20...=0A-=20*/=0A-#ifdef=20=
TLS1_3_VERSION=0A-#error=20OpenSSL=20version=20mismatch=0A-#endif=0A-=0A=
-static=20int=0A-SSL_CTX_set_min_proto_version(SSL_CTX=20*ctx,=20int=20=
version)=0A-{=0A-=09int=09=09=09ssl_options=20=3D=20SSL_OP_NO_SSLv2=20|=20=
SSL_OP_NO_SSLv3;=0A-=0A-=09if=20(version=20>=20TLS1_VERSION)=0A-=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1;=0A-=09/*=0A-=09=20*=20Some=20=
OpenSSL=20versions=20define=20TLS*_VERSION=20macros=20but=20not=20the=0A=
-=09=20*=20corresponding=20SSL_OP_NO_*=20macro,=20so=20in=20those=20=
cases=20we=20have=20to=20return=0A-=09=20*=20unsuccessfully=20here.=0A-=09=
=20*/=0A-#ifdef=20TLS1_1_VERSION=0A-=09if=20(version=20>=20=
TLS1_1_VERSION)=0A-=09{=0A-#ifdef=20SSL_OP_NO_TLSv1_1=0A-=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_1;=0A-#else=0A-=09=09return=200;=0A=
-#endif=0A-=09}=0A-#endif=0A-#ifdef=20TLS1_2_VERSION=0A-=09if=20(version=20=
>=20TLS1_2_VERSION)=0A-=09{=0A-#ifdef=20SSL_OP_NO_TLSv1_2=0A-=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_2;=0A-#else=0A-=09=09return=200;=0A=
-#endif=0A-=09}=0A-#endif=0A-=0A-=09SSL_CTX_set_options(ctx,=20=
ssl_options);=0A-=0A-=09return=201;=09=09=09=09=09/*=20success=20*/=0A-}=0A=
-=0A-static=20int=0A-SSL_CTX_set_max_proto_version(SSL_CTX=20*ctx,=20int=20=
version)=0A-{=0A-=09int=09=09=09ssl_options=20=3D=200;=0A-=0A-=09=
AssertArg(version=20!=3D=200);=0A-=0A-=09/*=0A-=09=20*=20Some=20OpenSSL=20=
versions=20define=20TLS*_VERSION=20macros=20but=20not=20the=0A-=09=20*=20=
corresponding=20SSL_OP_NO_*=20macro,=20so=20in=20those=20cases=20we=20=
have=20to=20return=0A-=09=20*=20unsuccessfully=20here.=0A-=09=20*/=0A=
-#ifdef=20TLS1_1_VERSION=0A-=09if=20(version=20<=20TLS1_1_VERSION)=0A-=09=
{=0A-#ifdef=20SSL_OP_NO_TLSv1_1=0A-=09=09ssl_options=20|=3D=20=
SSL_OP_NO_TLSv1_1;=0A-#else=0A-=09=09return=200;=0A-#endif=0A-=09}=0A=
-#endif=0A-#ifdef=20TLS1_2_VERSION=0A-=09if=20(version=20<=20=
TLS1_2_VERSION)=0A-=09{=0A-#ifdef=20SSL_OP_NO_TLSv1_2=0A-=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_2;=0A-#else=0A-=09=09return=200;=0A=
-#endif=0A-=09}=0A-#endif=0A-=0A-=09SSL_CTX_set_options(ctx,=20=
ssl_options);=0A-=0A-=09return=201;=09=09=09=09=09/*=20success=20*/=0A-}=0A=
-=0A-#endif=09=09=09=09=09=09=09/*=20!SSL_CTX_set_min_proto_version=20*/=0A=
diff=20--git=20a/src/common/Makefile=20b/src/common/Makefile=0Aindex=20=
ffb0f6edff..bec9c47aef=20100644=0A---=20a/src/common/Makefile=0A+++=20=
b/src/common/Makefile=0A@@=20-73,7=20+73,8=20@@=20OBJS_COMMON=20=3D=20\=0A=
=20=09wait_error.o=0A=20=0A=20ifeq=20($(with_openssl),yes)=0A=
-OBJS_COMMON=20+=3D=20sha2_openssl.o=0A+OBJS_COMMON=20+=3D=20=
sha2_openssl.o=20\=0A+=09protocol_openssl.o=0A=20else=0A=20OBJS_COMMON=20=
+=3D=20sha2.o=0A=20endif=0Adiff=20--git=20=
a/src/common/protocol_openssl.c=20b/src/common/protocol_openssl.c=0Anew=20=
file=20mode=20100644=0Aindex=200000000000..b55919a215=0A---=20/dev/null=0A=
+++=20b/src/common/protocol_openssl.c=0A@@=20-0,0=20+1,115=20@@=0A=
+/*-----------------------------------------------------------------------=
--=0A+=20*=0A+=20*=20protocol_openssl.c=0A+=20*=09=20=20OpenSSL=20=
functionality=20shared=20between=20frontend=20and=20backend=0A+=20*=0A+=20=
*=20This=20should=20only=20be=20used=20if=20code=20is=20compiled=20with=20=
OpenSSL=20support.=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20=
2018-2020,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=0A+=20*=20=
IDENTIFICATION=0A+=20*=09=09=20=20src/common/protocol_openssl.c=0A+=20*=0A=
+=20=
*-------------------------------------------------------------------------=
=0A+=20*/=0A+=0A+#ifndef=20FRONTEND=0A+#include=20"postgres.h"=0A+#else=0A=
+#include=20"postgres_fe.h"=0A+#endif=0A+=0A+#include=20<openssl/ssl.h>=0A=
+=0A+/*=0A+=20*=20Replacements=20for=20APIs=20present=20in=20newer=20=
versions=20of=20OpenSSL=0A+=20*/=0A+#ifndef=20=
SSL_CTX_set_min_proto_version=0A+=0A+/*=0A+=20*=20OpenSSL=20versions=20=
that=20support=20TLS=201.3=20shouldn't=20get=20here=20because=20they=0A+=20=
*=20already=20have=20these=20functions.=20=20So=20we=20don't=20have=20to=20=
keep=20updating=20the=20below=0A+=20*=20code=20for=20every=20new=20TLS=20=
version,=20and=20eventually=20it=20can=20go=20away.=20=20But=20let's=0A+=20=
*=20just=20check=20this=20to=20make=20sure=20...=0A+=20*/=0A+#ifdef=20=
TLS1_3_VERSION=0A+#error=20OpenSSL=20version=20mismatch=0A+#endif=0A+=0A=
+static=20int=0A+SSL_CTX_set_min_proto_version(SSL_CTX=20*ctx,=20int=20=
version)=0A+{=0A+=09int=09=09=09ssl_options=20=3D=20SSL_OP_NO_SSLv2=20|=20=
SSL_OP_NO_SSLv3;=0A+=0A+=09if=20(version=20>=20TLS1_VERSION)=0A+=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1;=0A+=09/*=0A+=09=20*=20Some=20=
OpenSSL=20versions=20define=20TLS*_VERSION=20macros=20but=20not=20the=0A=
+=09=20*=20corresponding=20SSL_OP_NO_*=20macro,=20so=20in=20those=20=
cases=20we=20have=20to=20return=0A+=09=20*=20unsuccessfully=20here.=0A+=09=
=20*/=0A+#ifdef=20TLS1_1_VERSION=0A+=09if=20(version=20>=20=
TLS1_1_VERSION)=0A+=09{=0A+#ifdef=20SSL_OP_NO_TLSv1_1=0A+=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_1;=0A+#else=0A+=09=09return=200;=0A=
+#endif=0A+=09}=0A+#endif=0A+#ifdef=20TLS1_2_VERSION=0A+=09if=20(version=20=
>=20TLS1_2_VERSION)=0A+=09{=0A+#ifdef=20SSL_OP_NO_TLSv1_2=0A+=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_2;=0A+#else=0A+=09=09return=200;=0A=
+#endif=0A+=09}=0A+#endif=0A+=0A+=09SSL_CTX_set_options(ctx,=20=
ssl_options);=0A+=0A+=09return=201;=09=09=09=09=09/*=20success=20*/=0A+}=0A=
+=0A+static=20int=0A+SSL_CTX_set_max_proto_version(SSL_CTX=20*ctx,=20int=20=
version)=0A+{=0A+=09int=09=09=09ssl_options=20=3D=200;=0A+=0A+=09=
AssertArg(version=20!=3D=200);=0A+=0A+=09/*=0A+=09=20*=20Some=20OpenSSL=20=
versions=20define=20TLS*_VERSION=20macros=20but=20not=20the=0A+=09=20*=20=
corresponding=20SSL_OP_NO_*=20macro,=20so=20in=20those=20cases=20we=20=
have=20to=20return=0A+=09=20*=20unsuccessfully=20here.=0A+=09=20*/=0A=
+#ifdef=20TLS1_1_VERSION=0A+=09if=20(version=20<=20TLS1_1_VERSION)=0A+=09=
{=0A+#ifdef=20SSL_OP_NO_TLSv1_1=0A+=09=09ssl_options=20|=3D=20=
SSL_OP_NO_TLSv1_1;=0A+#else=0A+=09=09return=200;=0A+#endif=0A+=09}=0A=
+#endif=0A+#ifdef=20TLS1_2_VERSION=0A+=09if=20(version=20<=20=
TLS1_2_VERSION)=0A+=09{=0A+#ifdef=20SSL_OP_NO_TLSv1_2=0A+=09=09=
ssl_options=20|=3D=20SSL_OP_NO_TLSv1_2;=0A+#else=0A+=09=09return=200;=0A=
+#endif=0A+=09}=0A+#endif=0A+=0A+=09SSL_CTX_set_options(ctx,=20=
ssl_options);=0A+=0A+=09return=201;=09=09=09=09=09/*=20success=20*/=0A+}=0A=
+=0A+#endif=09=09=09=09=09=09=09/*=20!SSL_CTX_set_min_proto_version=20*/=0A=
diff=20--git=20a/src/include/common/openssl.h=20=
b/src/include/common/openssl.h=0Anew=20file=20mode=20100644=0Aindex=20=
0000000000..bf37f8d56c=0A---=20/dev/null=0A+++=20=
b/src/include/common/openssl.h=0A@@=20-0,0=20+1,27=20@@=0A=
+/*-----------------------------------------------------------------------=
--=0A+=20*=0A+=20*=20openssl.h=0A+=20*=09=20=20OpenSSL=20supporting=20=
functionality=20shared=20between=20frontend=20and=20backend=0A+=20*=0A+=20=
*=20Portions=20Copyright=20(c)=202018-2020,=20PostgreSQL=20Global=20=
Development=20Group=0A+=20*=0A+=20*=20IDENTIFICATION=0A+=20*=09=09=20=20=
src/include/common/openssl.h=0A+=20*=0A+=20=
*-------------------------------------------------------------------------=
=0A+=20*/=0A+#ifndef=20COMMON_OPENSSL_H=0A+#define=20COMMON_OPENSSL_H=0A=
+=0A+#ifdef=20USE_OPENSSL=0A+#include=20<openssl/ssl.h>=0A+=0A+/*=20=
src/common/protocol_openssl.c=20*/=0A+#ifndef=20=
SSL_CTX_set_min_proto_version=0A+static=20int=20=
SSL_CTX_set_min_proto_version(SSL_CTX=20*ctx,=20int=20version);=0A=
+static=20int=20SSL_CTX_set_max_proto_version(SSL_CTX=20*ctx,=20int=20=
version);=0A+#endif=0A+=0A+#endif=0A+=0A+#endif=09=09=09=09=09=09=09/*=20=
COMMON_OPENSSL_H=20*/=0Adiff=20--git=20=
a/src/interfaces/libpq/fe-connect.c=20=
b/src/interfaces/libpq/fe-connect.c=0Aindex=2080b54bc92b..a635639580=20=
100644=0A---=20a/src/interfaces/libpq/fe-connect.c=0A+++=20=
b/src/interfaces/libpq/fe-connect.c=0A@@=20-320,6=20+320,14=20@@=20=
static=20const=20internalPQconninfoOption=20PQconninfoOptions[]=20=3D=20=
{=0A=20=09=09"Require-Peer",=20"",=2010,=0A=20=09offsetof(struct=20=
pg_conn,=20requirepeer)},=0A=20=0A+=09{"sslminprotocolversion",=20=
"PGSSLMINPROTOCOLVERSION",=20NULL,=20NULL,=0A+=09=09=
"SSL-Minimum-Protocol-Version",=20"",=20=20/*=20sizeof("tlsv1.x")=20*/=20=
7,=0A+=09offsetof(struct=20pg_conn,=20sslminprotocolversion)},=0A+=0A+=09=
{"sslmaxprotocolversion",=20"PGSSLMAXPROTOCOLVERSION",=20NULL,=20NULL,=0A=
+=09=09"SSL-Maximum-Protocol-Version",=20"",=20/*=20sizeof("tlvs1.x")=20=
*/=207,=0A+=09offsetof(struct=20pg_conn,=20sslmaxprotocolversion)},=0A+=0A=
=20=09/*=0A=20=09=20*=20As=20with=20SSL,=20all=20GSS=20options=20are=20=
exposed=20even=20in=20builds=20that=20don't=20have=0A=20=09=20*=20=
support.=0Adiff=20--git=20a/src/interfaces/libpq/fe-secure-openssl.c=20=
b/src/interfaces/libpq/fe-secure-openssl.c=0Aindex=20=
0e84fc8ac6..f20d8fa287=20100644=0A---=20=
a/src/interfaces/libpq/fe-secure-openssl.c=0A+++=20=
b/src/interfaces/libpq/fe-secure-openssl.c=0A@@=20-30,6=20+30,7=20@@=0A=20=
#include=20"fe-auth.h"=0A=20#include=20"fe-secure-common.h"=0A=20=
#include=20"libpq-int.h"=0A+#include=20"common/openssl.h"=0A=20=0A=20=
#ifdef=20WIN32=0A=20#include=20"win32.h"=0A@@=20-95,6=20+96,7=20@@=20=
static=20long=20win32_ssl_create_mutex=20=3D=200;=0A=20#endif=09=09=09=09=
=09=09=09/*=20ENABLE_THREAD_SAFETY=20*/=0A=20=0A=20static=20=
PQsslKeyPassHook_type=20PQsslKeyPassHook=20=3D=20NULL;=0A+static=20int=20=
ssl_protocol_version_to_openssl(const=20char=20*protocol);=0A=20=0A=20/*=20=
------------------------------------------------------------=20*/=0A=20=
/*=09=09=09=20Procedures=20common=20to=20all=20secure=20sessions=09=09=09=
*/=0A@@=20-787,6=20+789,8=20@@=20initialize_SSL(PGconn=20*conn)=0A=20=09=
bool=09=09have_cert;=0A=20=09bool=09=09have_rootcert;=0A=20=09EVP_PKEY=20=
=20=20*pkey=20=3D=20NULL;=0A+=09int=09=09=09ssl_max_ver;=0A+=09int=09=09=09=
ssl_min_ver;=0A=20=0A=20=09/*=0A=20=09=20*=20We'll=20need=20the=20home=20=
directory=20if=20any=20of=20the=20relevant=20parameters=20are=0A@@=20=
-843,6=20+847,52=20@@=20initialize_SSL(PGconn=20*conn)=0A=20=09/*=20=
Disable=20old=20protocol=20versions=20*/=0A=20=09=
SSL_CTX_set_options(SSL_context,=20SSL_OP_NO_SSLv2=20|=20=
SSL_OP_NO_SSLv3);=0A=20=0A+=09if=20(conn->sslminprotocolversion)=0A+=09{=0A=
+=09=09ssl_min_ver=20=3D=20=
ssl_protocol_version_to_openssl(conn->sslminprotocolversion);=0A+=0A+=09=09=
if=20(ssl_min_ver=20=3D=3D=20-1)=0A+=09=09{=0A+=09=09=09=
printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=09=20=20=
libpq_gettext("invalid=20minimum=20protocol=20version=20specified:=20=
%s\n"),=0A+=09=09=09=09=09=09=09=20=20conn->sslminprotocolversion);=0A+=09=
=09=09return=20-1;=0A+=09=09}=0A+=0A+=09=09if=20=
(!SSL_CTX_set_min_proto_version(SSL_context,=20ssl_min_ver))=0A+=09=09{=0A=
+=09=09=09char=09=20=20=20*err=20=3D=20SSLerrmessage(ERR_get_error());=0A=
+=0A+=09=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=
=09=20=20libpq_gettext("unable=20to=20set=20minimum=20protocol=20version=20=
specified:=20%s\n"),=0A+=09=09=09=09=09=09=09=20=20err);=0A+=09=09=09=
return=20-1;=0A+=09=09}=0A+=09}=0A+=0A+=09if=20=
(conn->sslmaxprotocolversion)=0A+=09{=0A+=09=09ssl_max_ver=20=3D=20=
ssl_protocol_version_to_openssl(conn->sslmaxprotocolversion);=0A+=0A+=09=09=
if=20(ssl_max_ver=20=3D=3D=20-1)=0A+=09=09{=0A+=09=09=09=
printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=09=20=20=
libpq_gettext("invalid=20or=20unsupported=20maximum=20protocol=20version=20=
specified:=20%s\n"),=0A+=09=09=09=09=09=09=09=20=20=
conn->sslmaxprotocolversion);=0A+=09=09=09return=20-1;=0A+=09=09}=0A+=0A=
+=09=09if=20(!SSL_CTX_set_max_proto_version(SSL_context,=20ssl_max_ver))=0A=
+=09=09{=0A+=09=09=09char=09=20=20=20*err=20=3D=20=
SSLerrmessage(ERR_get_error());=0A+=0A+=09=09=09=
printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=09=20=20=
libpq_gettext("unable=20to=20set=20maximum=20SSL=20version=20specified:=20=
%s\n"),=0A+=09=09=09=09=09=09=09=20=20err);=0A+=09=09=09return=20-1;=0A+=09=
=09}=0A+=09}=0A+=0A=20=09/*=0A=20=09=20*=20Disable=20OpenSSL's=20=
moving-write-buffer=20sanity=20check,=20because=20it=20causes=0A=20=09=20=
*=20unnecessary=20failures=20in=20nonblocking=20send=20cases.=0A@@=20=
-1659,3=20+1709,34=20@@=20PQssl_passwd_cb(char=20*buf,=20int=20size,=20=
int=20rwflag,=20void=20*userdata)=0A=20=09else=0A=20=09=09return=20=
PQdefaultSSLKeyPassHook(buf,=20size,=20conn);=0A=20}=0A+=0A+/*=0A+=20*=20=
Convert=20TLS=20protocol=20versionstring=20to=20OpenSSL=20values=0A+=20*=0A=
+=20*=20If=20a=20version=20is=20passed=20that=20is=20not=20supported=20=
by=20the=20current=20OpenSSL=20version,=0A+=20*=20then=20we=20return=20=
-1.=20If=20a=20nonnegative=20value=20is=20returned,=20subsequent=20code=20=
can=0A+=20*=20assume=20it's=20working=20with=20a=20supported=20version.=0A=
+=20*/=0A+static=20int=0A+ssl_protocol_version_to_openssl(const=20char=20=
*protocol)=0A+{=0A+=09if=20((pg_strcasecmp("tlsv1",=20protocol)=20=3D=3D=20=
0)=20||=20pg_strcasecmp("tlsv1.0",=20protocol)=20=3D=3D=200)=0A+=09=09=
return=20TLS1_VERSION;=0A+=0A+#ifdef=20TLS1_1_VERSION=0A+=09if=20=
(pg_strcasecmp("tlsv1.1",=20protocol)=20=3D=3D=200)=0A+=09=09return=20=
TLS1_1_VERSION;=0A+#endif=0A+=0A+#ifdef=20TLS1_2_VERSION=0A+=09if=20=
(pg_strcasecmp("tlsv1.2",=20protocol)=20=3D=3D=200)=0A+=09=09return=20=
TLS1_2_VERSION;=0A+#endif=0A+=0A+#ifdef=20TLS1_3_VERSION=0A+=09if=20=
(pg_strcasecmp("tlsv1.3",=20protocol)=20=3D=3D=200)=0A+=09=09return=20=
TLS1_3_VERSION;=0A+#endif=0A+=0A+=09return=20-1;=0A+}=0Adiff=20--git=20=
a/src/interfaces/libpq/libpq-int.h=20b/src/interfaces/libpq/libpq-int.h=0A=
index=2079bc3780ff..72931e6019=20100644=0A---=20=
a/src/interfaces/libpq/libpq-int.h=0A+++=20=
b/src/interfaces/libpq/libpq-int.h=0A@@=20-367,6=20+367,8=20@@=20struct=20=
pg_conn=0A=20=09char=09=20=20=20*krbsrvname;=09=09/*=20Kerberos=20=
service=20name=20*/=0A=20=09char=09=20=20=20*gsslib;=09=09=09/*=20What=20=
GSS=20library=20to=20use=20("gssapi"=20or=0A=20=09=09=09=09=09=09=09=09=20=
*=20"sspi")=20*/=0A+=09char=09=20=20=20*sslminprotocolversion;=09/*=20=
minimum=20TLS=20protocol=20version=20*/=0A+=09char=09=20=20=20=
*sslmaxprotocolversion;=09/*=20maximum=20TLS=20protocol=20version=20*/=0A=
=20=0A=20=09/*=20Type=20of=20connection=20to=20make.=20=20Possible=20=
values:=20any,=20read-write.=20*/=0A=20=09char=09=20=20=20=
*target_session_attrs;=0Adiff=20--git=20a/src/test/ssl/t/001_ssltests.pl=20=
b/src/test/ssl/t/001_ssltests.pl=0Aindex=2083fcd5e839..e7726bccfe=20=
100644=0A---=20a/src/test/ssl/t/001_ssltests.pl=0A+++=20=
b/src/test/ssl/t/001_ssltests.pl=0A@@=20-13,7=20+13,7=20@@=20use=20=
SSLServer;=0A=20=0A=20if=20($ENV{with_openssl}=20eq=20'yes')=0A=20{=0A-=09=
plan=20tests=20=3D>=2084;=0A+=09plan=20tests=20=3D>=2087;=0A=20}=0A=20=
else=0A=20{=0A@@=20-338,6=20+338,18=20@@=20command_like(=0A=20=09=09=09=09=
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,_null_,_null_,_null_\r?$}mx,=0A=20=09=
'pg_stat_ssl=20view=20without=20client=20certificate');=0A=20=0A+#=20=
Test=20min/mix=20protocol=20versions=0A+test_connect_ok(=0A+=09=
$common_connstr,=0A+=09"sslrootcert=3Dssl/root+server_ca.crt=20=
sslmode=3Drequire=20sslminprotocolversion=3Dtlsv1.2=20=
sslmaxprotocolversion=3Dtlsv1.3",=0A+=09"connect=20with=20correct=20=
range=20of=20allowed=20TLS=20protocol=20versions");=0A+=0A=
+test_connect_fails(=0A+=09$common_connstr,=0A+=09=
"sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20=
sslminprotocolversion=3Dtlsv1.3=20sslmaxprotocolversion=3Dtlsv1.2",=0A+=09=
qr/SSL=20error/,=0A+=09"connect=20with=20an=20incorrect=20range=20of=20=
TLS=20protocol=20versions=20leaving=20no=20versions=20allowed");=0A+=0A=20=
###=20Server-side=20tests.=0A=20###=0A=20###=20Test=20certificate=20=
authorization.=0Adiff=20--git=20a/src/tools/msvc/Mkvcbuild.pm=20=
b/src/tools/msvc/Mkvcbuild.pm=0Aindex=203d6ef0de84..d3bc6c92d5=20100644=0A=
---=20a/src/tools/msvc/Mkvcbuild.pm=0A+++=20=
b/src/tools/msvc/Mkvcbuild.pm=0A@@=20-129,6=20+129,7=20@@=20sub=20=
mkvcbuild=0A=20=09if=20($solution->{options}->{openssl})=0A=20=09{=0A=20=09=
=09push(@pgcommonallfiles,=20'sha2_openssl.c');=0A+=09=09=
push(@pgcommonallfiles,=20'protocol_openssl.c');=0A=20=09}=0A=20=09else=0A=
=20=09{=0A--=20=0A2.21.0=20(Apple=20Git-122.2)=0A=0A=

--Apple-Mail=_22F5B6EA-FF0D-46DC-9F32-D92CD5987730--