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--