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 1jrKEJ-0002qz-7Z for pgsql-hackers@arkaria.postgresql.org; Fri, 03 Jul 2020 11:51:43 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jrKEI-0000I9-5Q for pgsql-hackers@arkaria.postgresql.org; Fri, 03 Jul 2020 11:51:42 +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 1jrKEH-0000Hx-7t for pgsql-hackers@lists.postgresql.org; Fri, 03 Jul 2020 11:51:41 +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 1jrKED-0001sl-5u for pgsql-hackers@lists.postgresql.org; Fri, 03 Jul 2020 11:51:40 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id 76C262F6632C for ; Fri, 3 Jul 2020 13:51:32 +0200 (CEST) Received: from s499.loopia.se (unknown [172.22.191.6]) by s807.loopia.se (Postfix) with ESMTP id 57F532E28A2B; Fri, 3 Jul 2020 13:51:32 +0200 (CEST) Received: from s470.loopia.se (unknown [172.22.191.6]) by s499.loopia.se (Postfix) with ESMTP id 4E1011CDAF97; Fri, 3 Jul 2020 13:51:32 +0200 (CEST) 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 s498.loopia.se ([172.22.191.6]) by s470.loopia.se (s470.loopia.se [172.22.190.10]) (amavisd-new, port 10024) with LMTP id s32afbsCq8OC; Fri, 3 Jul 2020 13:51:30 +0200 (CEST) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 94.234.33.208 Received: from [192.168.1.100] (unknown [94.234.33.208]) (Authenticated sender: daniel@yesql.se) by s498.loopia.se (Postfix) with ESMTPSA id 80E5F47089B; Fri, 3 Jul 2020 13:51:29 +0200 (CEST) From: Daniel Gustafsson Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_DD4256D0-7992-400E-A089-6CE7D4CD6E3E" Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.14\)) Subject: Re: Support for NSS as a libpq TLS backend Date: Fri, 3 Jul 2020 13:51:28 +0200 In-Reply-To: Cc: Stephen Frost To: Postgres hackers References: X-Mailer: Apple Mail (2.3445.104.14) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --Apple-Mail=_DD4256D0-7992-400E-A089-6CE7D4CD6E3E Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 25 Jun 2020, at 17:39, Daniel Gustafsson wrote: >=20 >> On 15 May 2020, at 22:46, Daniel Gustafsson wrote: >=20 >> The 0001 patch contains the full NSS support, and 0002 is a fix for = the pgstat >> abstraction which IMO leaks backend implementation details. This = needs to go >> on it's own thread, but since 0001 fails without it I've included it = here for >> simplicity sake for now. >=20 > The attached 0001 and 0002 are the same patchseries as before, but = with the > OpenSSL test module fixed and a rebase on top of the current master. Another rebase to resolve conflicts with the recent fixes in the SSL = tests, as well as some minor cleanup. cheers ./daniel --Apple-Mail=_DD4256D0-7992-400E-A089-6CE7D4CD6E3E Content-Disposition: attachment; filename=0002-Make-pg_stat_ssl-reporting-backend-agnostic-v3.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0002-Make-pg_stat_ssl-reporting-backend-agnostic-v3.patch" Content-Transfer-Encoding: quoted-printable =46rom=20b2c489f9715d647f709ddcb888ec1d64c231ddca=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20=0A= Date:=20Fri,=203=20Jul=202020=2013:42:21=20+0200=0ASubject:=20[PATCH=20= 2/2]=20Make=20pg_stat_ssl=20reporting=20backend=20agnostic=20v3=0A=0A= Inspecting=20Port->ssl=20for=20an=20indication=20on=20whether=20the=20= connection=20is=0Ausing=20TLS=20or=20not=20is=20tied=20to=20the=20fact=20= that=20the=20current=20implementation=0Ais=20using=20a=20variable=20= named=20ssl.=20Making=20this=20a=20requirement=20for=20all=20TLS=0A= backend=20implementations=20seems=20restricting=20since=20there=20in=20= actual=20var=0Atracking=20the=20status,=20ssl_in_use.=20Switch=20to=20= inspecting=20this=20variable=0Ainstead.=0A---=0A=20= src/backend/postmaster/pgstat.c=20|=202=20+-=0A=201=20file=20changed,=20= 1=20insertion(+),=201=20deletion(-)=0A=0Adiff=20--git=20= a/src/backend/postmaster/pgstat.c=20b/src/backend/postmaster/pgstat.c=0A= index=20c022597bc0..edfa774ee4=20100644=0A---=20= a/src/backend/postmaster/pgstat.c=0A+++=20= b/src/backend/postmaster/pgstat.c=0A@@=20-2989,7=20+2989,7=20@@=20= pgstat_bestart(void)=0A=20=09=09MemSet(&lbeentry.st_clientaddr,=200,=20= sizeof(lbeentry.st_clientaddr));=0A=20=0A=20#ifdef=20USE_SSL=0A-=09if=20= (MyProcPort=20&&=20MyProcPort->ssl=20!=3D=20NULL)=0A+=09if=20(MyProcPort=20= &&=20MyProcPort->ssl_in_use)=0A=20=09{=0A=20=09=09lbeentry.st_ssl=20=3D=20= true;=0A=20=09=09lsslstatus.ssl_bits=20=3D=20= be_tls_get_cipher_bits(MyProcPort);=0A--=20=0A2.21.1=20(Apple=20= Git-122.3)=0A=0A= --Apple-Mail=_DD4256D0-7992-400E-A089-6CE7D4CD6E3E Content-Disposition: attachment; filename=0001-WIP-Support-libnss-for-as-TLS-backend-v3.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-WIP-Support-libnss-for-as-TLS-backend-v3.patch" Content-Transfer-Encoding: quoted-printable =46rom=2020531c638da852348c629f2e2d2f6fbb2014f2c6=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20=0A= Date:=20Fri,=203=20Jul=202020=2013:34:27=20+0200=0ASubject:=20[PATCH=20= 1/2]=20WIP:=20Support=20libnss=20for=20as=20TLS=20backend=20v3=0A=0A---=0A= =20configure=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20235=20+++-=0A=20= configure.in=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=2030=20+=0A=20= src/Makefile.global.in=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20src/backend/libpq/Makefile=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=204=20= +=0A=20src/backend/libpq/auth.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=20=207=20+=0A=20= src/backend/libpq/be-secure-nss.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=201026=20+++++++++++++++++=0A=20src/backend/libpq/be-secure.c=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=203=20+=0A=20= src/backend/utils/misc/guc.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=2020=20+-=0A=20src/include/common/pg_nss.h=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20141=20+++=0A=20= src/include/libpq/libpq-be.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=20=209=20+-=0A=20src/include/libpq/libpq.h=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=20= src/include/pg_config.h.in=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/include/pg_config_manual.h=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=205=20+-=0A=20= src/interfaces/libpq/Makefile=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=20=204=20+=0A=20src/interfaces/libpq/fe-connect.c=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=20=20=206=20+=0A=20= src/interfaces/libpq/fe-secure-nss.c=20=20=20=20=20=20=20=20=20=20|=20=20= 959=20+++++++++++++++=0A=20src/interfaces/libpq/libpq-fe.h=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=2011=20+=0A=20= src/interfaces/libpq/libpq-int.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=20=205=20+=0A=20src/test/ssl/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=20|=20=20157=20+++=0A=20= src/test/ssl/t/001_ssltests.pl=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20203=20++--=0A=20src/test/ssl/t/002_scram.pl=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=204=20+-=0A=20= src/test/ssl/t/SSL/Backend/NSS.pm=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=2065=20++=0A=20src/test/ssl/t/SSL/Backend/OpenSSL.pm=20=20=20=20=20= =20=20=20=20|=20=20102=20++=0A=20.../ssl/t/{SSLServer.pm=20=3D>=20= SSL/Server.pm}=20=20=20=20=20|=20=20=2060=20+-=0A=2024=20files=20= changed,=202934=20insertions(+),=20129=20deletions(-)=0A=20create=20mode=20= 100644=20src/backend/libpq/be-secure-nss.c=0A=20create=20mode=20100644=20= src/include/common/pg_nss.h=0A=20create=20mode=20100644=20= src/interfaces/libpq/fe-secure-nss.c=0A=20create=20mode=20100644=20= src/test/ssl/t/SSL/Backend/NSS.pm=0A=20create=20mode=20100644=20= src/test/ssl/t/SSL/Backend/OpenSSL.pm=0A=20rename=20= src/test/ssl/t/{SSLServer.pm=20=3D>=20SSL/Server.pm}=20(82%)=0A=0Adiff=20= --git=20a/configure=20b/configure=0Aindex=202feff37fe3..3f6520ae34=20= 100755=0A---=20a/configure=0A+++=20b/configure=0A@@=20-711,6=20+711,7=20= @@=20with_uuid=0A=20with_readline=0A=20with_systemd=0A=20with_selinux=0A= +with_nss=0A=20with_openssl=0A=20with_ldap=0A=20with_krb_srvnam=0A@@=20= -798,6=20+799,7=20@@=20infodir=0A=20docdir=0A=20oldincludedir=0A=20= includedir=0A+runstatedir=0A=20localstatedir=0A=20sharedstatedir=0A=20= sysconfdir=0A@@=20-856,6=20+858,7=20@@=20with_bsd_auth=0A=20with_ldap=0A=20= with_bonjour=0A=20with_openssl=0A+with_nss=0A=20with_selinux=0A=20= with_systemd=0A=20with_readline=0A@@=20-935,6=20+938,7=20@@=20= datadir=3D'${datarootdir}'=0A=20sysconfdir=3D'${prefix}/etc'=0A=20= sharedstatedir=3D'${prefix}/com'=0A=20localstatedir=3D'${prefix}/var'=0A= +runstatedir=3D'${localstatedir}/run'=0A=20= includedir=3D'${prefix}/include'=0A=20oldincludedir=3D'/usr/include'=0A=20= docdir=3D'${datarootdir}/doc/${PACKAGE_TARNAME}'=0A@@=20-1187,6=20= +1191,15=20@@=20do=0A=20=20=20|=20-silent=20|=20--silent=20|=20--silen=20= |=20--sile=20|=20--sil)=0A=20=20=20=20=20silent=3Dyes=20;;=0A=20=0A+=20=20= -runstatedir=20|=20--runstatedir=20|=20--runstatedi=20|=20--runstated=20= \=0A+=20=20|=20--runstate=20|=20--runstat=20|=20--runsta=20|=20--runst=20= |=20--runs=20\=0A+=20=20|=20--run=20|=20--ru=20|=20--r)=0A+=20=20=20=20= ac_prev=3Drunstatedir=20;;=0A+=20=20-runstatedir=3D*=20|=20= --runstatedir=3D*=20|=20--runstatedi=3D*=20|=20--runstated=3D*=20\=0A+=20= =20|=20--runstate=3D*=20|=20--runstat=3D*=20|=20--runsta=3D*=20|=20= --runst=3D*=20|=20--runs=3D*=20\=0A+=20=20|=20--run=3D*=20|=20--ru=3D*=20= |=20--r=3D*)=0A+=20=20=20=20runstatedir=3D$ac_optarg=20;;=0A+=0A=20=20=20= -sbindir=20|=20--sbindir=20|=20--sbindi=20|=20--sbind=20|=20--sbin=20|=20= --sbi=20|=20--sb)=0A=20=20=20=20=20ac_prev=3Dsbindir=20;;=0A=20=20=20= -sbindir=3D*=20|=20--sbindir=3D*=20|=20--sbindi=3D*=20|=20--sbind=3D*=20= |=20--sbin=3D*=20\=0A@@=20-1324,7=20+1337,7=20@@=20fi=0A=20for=20ac_var=20= in=09exec_prefix=20prefix=20bindir=20sbindir=20libexecdir=20datarootdir=20= \=0A=20=09=09datadir=20sysconfdir=20sharedstatedir=20localstatedir=20= includedir=20\=0A=20=09=09oldincludedir=20docdir=20infodir=20htmldir=20= dvidir=20pdfdir=20psdir=20\=0A-=09=09libdir=20localedir=20mandir=0A+=09=09= libdir=20localedir=20mandir=20runstatedir=0A=20do=0A=20=20=20eval=20= ac_val=3D\$$ac_var=0A=20=20=20#=20Remove=20trailing=20slashes.=0A@@=20= -1477,6=20+1490,7=20@@=20Fine=20tuning=20of=20the=20installation=20= directories:=0A=20=20=20--sysconfdir=3DDIR=20=20=20=20=20=20=20=20= read-only=20single-machine=20data=20[PREFIX/etc]=0A=20=20=20= --sharedstatedir=3DDIR=20=20=20=20modifiable=20architecture-independent=20= data=20[PREFIX/com]=0A=20=20=20--localstatedir=3DDIR=20=20=20=20=20= modifiable=20single-machine=20data=20[PREFIX/var]=0A+=20=20= --runstatedir=3DDIR=20=20=20=20=20=20=20modifiable=20per-process=20data=20= [LOCALSTATEDIR/run]=0A=20=20=20--libdir=3DDIR=20=20=20=20=20=20=20=20=20=20= =20=20object=20code=20libraries=20[EPREFIX/lib]=0A=20=20=20= --includedir=3DDIR=20=20=20=20=20=20=20=20C=20header=20files=20= [PREFIX/include]=0A=20=20=20--oldincludedir=3DDIR=20=20=20=20=20C=20= header=20files=20for=20non-gcc=20[/usr/include]=0A@@=20-1558,6=20+1572,7=20= @@=20Optional=20Packages:=0A=20=20=20--with-ldap=20=20=20=20=20=20=20=20=20= =20=20=20=20build=20with=20LDAP=20support=0A=20=20=20--with-bonjour=20=20= =20=20=20=20=20=20=20=20build=20with=20Bonjour=20support=0A=20=20=20= --with-openssl=20=20=20=20=20=20=20=20=20=20build=20with=20OpenSSL=20= support=0A+=20=20--with-nss=20=20=20=20=20=20=20=20=20=20=20=20=20=20= build=20with=20NSS=20support=0A=20=20=20--with-selinux=20=20=20=20=20=20=20= =20=20=20build=20with=20SELinux=20support=0A=20=20=20--with-systemd=20=20= =20=20=20=20=20=20=20=20build=20with=20systemd=20support=0A=20=20=20= --without-readline=20=20=20=20=20=20do=20not=20use=20GNU=20Readline=20= nor=20BSD=20Libedit=20for=20editing=0A@@=20-8009,6=20+8024,41=20@@=20fi=0A= =20$as_echo=20"$with_openssl"=20>&6;=20}=0A=20=0A=20=0A+#=0A+#=20LibNSS=0A= +#=0A+{=20$as_echo=20"$as_me:${as_lineno-$LINENO}:=20checking=20whether=20= to=20build=20with=20NSS=20support"=20>&5=0A+$as_echo_n=20"checking=20= whether=20to=20build=20with=20NSS=20support...=20"=20>&6;=20}=0A+=0A+=0A= +=0A+#=20Check=20whether=20--with-nss=20was=20given.=0A+if=20test=20= "${with_nss+set}"=20=3D=20set;=20then=20:=0A+=20=20withval=3D$with_nss;=0A= +=20=20case=20$withval=20in=0A+=20=20=20=20yes)=0A+=0A+$as_echo=20= "#define=20USE_NSS=201"=20>>confdefs.h=0A+=0A+=20=20=20=20=20=20;;=0A+=20= =20=20=20no)=0A+=20=20=20=20=20=20:=0A+=20=20=20=20=20=20;;=0A+=20=20=20=20= *)=0A+=20=20=20=20=20=20as_fn_error=20$?=20"no=20argument=20expected=20= for=20--with-nss=20option"=20"$LINENO"=205=0A+=20=20=20=20=20=20;;=0A+=20= =20esac=0A+=0A+else=0A+=20=20with_nss=3Dno=0A+=0A+fi=0A+=0A+=0A+{=20= $as_echo=20"$as_me:${as_lineno-$LINENO}:=20result:=20$with_nss"=20>&5=0A= +$as_echo=20"$with_nss"=20>&6;=20}=0A+=0A+=0A=20#=0A=20#=20SELinux=0A=20= #=0A@@=20-12083,6=20+12133,9=20@@=20fi=0A=20fi=0A=20=0A=20if=20test=20= "$with_openssl"=20=3D=20yes=20;=20then=0A+=20=20if=20test=20x"$with_nss"=20= =3D=20x"yes"=20;=20then=0A+=20=20=20=20as_fn_error=20$?=20"multiple=20= SSL=20backends=20cannot=20be=20enabled=20simultaneously\""=20"$LINENO"=20= 5=0A+=20=20fi=0A=20=20=20=20=20if=20test=20"$PORTNAME"=20!=3D=20"win32";=20= then=0A=20=20=20=20=20=20{=20$as_echo=20"$as_me:${as_lineno-$LINENO}:=20= checking=20for=20CRYPTO_new_ex_data=20in=20-lcrypto"=20>&5=0A=20= $as_echo_n=20"checking=20for=20CRYPTO_new_ex_data=20in=20-lcrypto...=20"=20= >&6;=20}=0A@@=20-12341,6=20+12394,157=20@@=20done=0A=20=0A=20fi=0A=20=0A= +if=20test=20"$with_nss"=20=3D=20yes=20;=20then=0A+=20=20if=20test=20= x"$with_openssl"=20=3D=20x"yes"=20;=20then=0A+=20=20=20=20as_fn_error=20= $?=20"multiple=20SSL=20backends=20cannot=20be=20enabled=20= simultaneously\""=20"$LINENO"=205=0A+=20=20fi=0A+=20=20= CLEANLDFLAGS=3D"$LDFLAGS"=0A+=20=20#=20TODO:=20document=20this=20set=20= of=20LDFLAGS=0A+=20=20LDFLAGS=3D"-lssl3=20-lsmime3=20-lnss3=20-lplds4=20= -lplc4=20-lnspr4=20$LDFLAGS"=0A+=20=20{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20checking=20for=20SSL_VersionRangeSet=20= in=20-lnss3"=20>&5=0A+$as_echo_n=20"checking=20for=20SSL_VersionRangeSet=20= in=20-lnss3...=20"=20>&6;=20}=0A+if=20= ${ac_cv_lib_nss3_SSL_VersionRangeSet+:}=20false;=20then=20:=0A+=20=20= $as_echo_n=20"(cached)=20"=20>&6=0A+else=0A+=20=20= ac_check_lib_save_LIBS=3D$LIBS=0A+LIBS=3D"-lnss3=20=20$LIBS"=0A+cat=20= confdefs.h=20-=20<<_ACEOF=20>conftest.$ac_ext=0A+/*=20end=20confdefs.h.=20= =20*/=0A+=0A+/*=20Override=20any=20GCC=20internal=20prototype=20to=20= avoid=20an=20error.=0A+=20=20=20Use=20char=20because=20int=20might=20= match=20the=20return=20type=20of=20a=20GCC=0A+=20=20=20builtin=20and=20= then=20its=20argument=20prototype=20would=20still=20apply.=20=20*/=0A= +#ifdef=20__cplusplus=0A+extern=20"C"=0A+#endif=0A+char=20= SSL_VersionRangeSet=20();=0A+int=0A+main=20()=0A+{=0A+return=20= SSL_VersionRangeSet=20();=0A+=20=20;=0A+=20=20return=200;=0A+}=0A+_ACEOF=0A= +if=20ac_fn_c_try_link=20"$LINENO";=20then=20:=0A+=20=20= ac_cv_lib_nss3_SSL_VersionRangeSet=3Dyes=0A+else=0A+=20=20= ac_cv_lib_nss3_SSL_VersionRangeSet=3Dno=0A+fi=0A+rm=20-f=20core=20= conftest.err=20conftest.$ac_objext=20\=0A+=20=20=20=20conftest$ac_exeext=20= conftest.$ac_ext=0A+LIBS=3D$ac_check_lib_save_LIBS=0A+fi=0A+{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20result:=20= $ac_cv_lib_nss3_SSL_VersionRangeSet"=20>&5=0A+$as_echo=20= "$ac_cv_lib_nss3_SSL_VersionRangeSet"=20>&6;=20}=0A+if=20test=20= "x$ac_cv_lib_nss3_SSL_VersionRangeSet"=20=3D=20xyes;=20then=20:=0A+=20=20= cat=20>>confdefs.h=20<<_ACEOF=0A+#define=20HAVE_LIBNSS3=201=0A+_ACEOF=0A= +=0A+=20=20LIBS=3D"-lnss3=20$LIBS"=0A+=0A+else=0A+=20=20as_fn_error=20$?=20= "library=20'nss3'=20is=20required=20for=20NSS"=20"$LINENO"=205=0A+fi=0A+=0A= +=20=20{=20$as_echo=20"$as_me:${as_lineno-$LINENO}:=20checking=20for=20= PR_GetDefaultIOMethods=20in=20-lnspr4"=20>&5=0A+$as_echo_n=20"checking=20= for=20PR_GetDefaultIOMethods=20in=20-lnspr4...=20"=20>&6;=20}=0A+if=20= ${ac_cv_lib_nspr4_PR_GetDefaultIOMethods+:}=20false;=20then=20:=0A+=20=20= $as_echo_n=20"(cached)=20"=20>&6=0A+else=0A+=20=20= ac_check_lib_save_LIBS=3D$LIBS=0A+LIBS=3D"-lnspr4=20=20$LIBS"=0A+cat=20= confdefs.h=20-=20<<_ACEOF=20>conftest.$ac_ext=0A+/*=20end=20confdefs.h.=20= =20*/=0A+=0A+/*=20Override=20any=20GCC=20internal=20prototype=20to=20= avoid=20an=20error.=0A+=20=20=20Use=20char=20because=20int=20might=20= match=20the=20return=20type=20of=20a=20GCC=0A+=20=20=20builtin=20and=20= then=20its=20argument=20prototype=20would=20still=20apply.=20=20*/=0A= +#ifdef=20__cplusplus=0A+extern=20"C"=0A+#endif=0A+char=20= PR_GetDefaultIOMethods=20();=0A+int=0A+main=20()=0A+{=0A+return=20= PR_GetDefaultIOMethods=20();=0A+=20=20;=0A+=20=20return=200;=0A+}=0A= +_ACEOF=0A+if=20ac_fn_c_try_link=20"$LINENO";=20then=20:=0A+=20=20= ac_cv_lib_nspr4_PR_GetDefaultIOMethods=3Dyes=0A+else=0A+=20=20= ac_cv_lib_nspr4_PR_GetDefaultIOMethods=3Dno=0A+fi=0A+rm=20-f=20core=20= conftest.err=20conftest.$ac_objext=20\=0A+=20=20=20=20conftest$ac_exeext=20= conftest.$ac_ext=0A+LIBS=3D$ac_check_lib_save_LIBS=0A+fi=0A+{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20result:=20= $ac_cv_lib_nspr4_PR_GetDefaultIOMethods"=20>&5=0A+$as_echo=20= "$ac_cv_lib_nspr4_PR_GetDefaultIOMethods"=20>&6;=20}=0A+if=20test=20= "x$ac_cv_lib_nspr4_PR_GetDefaultIOMethods"=20=3D=20xyes;=20then=20:=0A+=20= =20cat=20>>confdefs.h=20<<_ACEOF=0A+#define=20HAVE_LIBNSPR4=201=0A= +_ACEOF=0A+=0A+=20=20LIBS=3D"-lnspr4=20$LIBS"=0A+=0A+else=0A+=20=20= as_fn_error=20$?=20"library=20'nspr4'=20is=20required=20for=20NSS"=20= "$LINENO"=205=0A+fi=0A+=0A+=20=20{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20checking=20for=20= SSL_GetImplementedCiphers=20in=20-lssl3"=20>&5=0A+$as_echo_n=20"checking=20= for=20SSL_GetImplementedCiphers=20in=20-lssl3...=20"=20>&6;=20}=0A+if=20= ${ac_cv_lib_ssl3_SSL_GetImplementedCiphers+:}=20false;=20then=20:=0A+=20=20= $as_echo_n=20"(cached)=20"=20>&6=0A+else=0A+=20=20= ac_check_lib_save_LIBS=3D$LIBS=0A+LIBS=3D"-lssl3=20=20$LIBS"=0A+cat=20= confdefs.h=20-=20<<_ACEOF=20>conftest.$ac_ext=0A+/*=20end=20confdefs.h.=20= =20*/=0A+=0A+/*=20Override=20any=20GCC=20internal=20prototype=20to=20= avoid=20an=20error.=0A+=20=20=20Use=20char=20because=20int=20might=20= match=20the=20return=20type=20of=20a=20GCC=0A+=20=20=20builtin=20and=20= then=20its=20argument=20prototype=20would=20still=20apply.=20=20*/=0A= +#ifdef=20__cplusplus=0A+extern=20"C"=0A+#endif=0A+char=20= SSL_GetImplementedCiphers=20();=0A+int=0A+main=20()=0A+{=0A+return=20= SSL_GetImplementedCiphers=20();=0A+=20=20;=0A+=20=20return=200;=0A+}=0A= +_ACEOF=0A+if=20ac_fn_c_try_link=20"$LINENO";=20then=20:=0A+=20=20= ac_cv_lib_ssl3_SSL_GetImplementedCiphers=3Dyes=0A+else=0A+=20=20= ac_cv_lib_ssl3_SSL_GetImplementedCiphers=3Dno=0A+fi=0A+rm=20-f=20core=20= conftest.err=20conftest.$ac_objext=20\=0A+=20=20=20=20conftest$ac_exeext=20= conftest.$ac_ext=0A+LIBS=3D$ac_check_lib_save_LIBS=0A+fi=0A+{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20result:=20= $ac_cv_lib_ssl3_SSL_GetImplementedCiphers"=20>&5=0A+$as_echo=20= "$ac_cv_lib_ssl3_SSL_GetImplementedCiphers"=20>&6;=20}=0A+if=20test=20= "x$ac_cv_lib_ssl3_SSL_GetImplementedCiphers"=20=3D=20xyes;=20then=20:=0A= +=20=20cat=20>>confdefs.h=20<<_ACEOF=0A+#define=20HAVE_LIBSSL3=201=0A= +_ACEOF=0A+=0A+=20=20LIBS=3D"-lssl3=20$LIBS"=0A+=0A+else=0A+=20=20= as_fn_error=20$?=20"library=20'ssl3'=20is=20required=20for=20NSS"=20= "$LINENO"=205=0A+fi=0A+=0A+=20=20LDFLAGS=3D"$CLEANLDFLAGS"=0A+fi=0A+=0A=20= if=20test=20"$with_pam"=20=3D=20yes=20;=20then=0A=20=20=20{=20$as_echo=20= "$as_me:${as_lineno-$LINENO}:=20checking=20for=20pam_start=20in=20-lpam"=20= >&5=0A=20$as_echo_n=20"checking=20for=20pam_start=20in=20-lpam...=20"=20= >&6;=20}=0A@@=20-13243,6=20+13447,25=20@@=20else=0A=20fi=0A=20=0A=20=0A= +fi=0A+=0A+if=20test=20"$with_nss"=20=3D=20yes=20;=20then=0A+=20=20= ac_fn_c_check_header_mongrel=20"$LINENO"=20"ssl.h"=20= "ac_cv_header_ssl_h"=20"$ac_includes_default"=0A+if=20test=20= "x$ac_cv_header_ssl_h"=20=3D=20xyes;=20then=20:=0A+=0A+else=0A+=20=20= as_fn_error=20$?=20"header=20file=20=20is=20required=20for=20NSS"=20= "$LINENO"=205=0A+fi=0A+=0A+=0A+=20=20ac_fn_c_check_header_mongrel=20= "$LINENO"=20"nss.h"=20"ac_cv_header_nss_h"=20"$ac_includes_default"=0A= +if=20test=20"x$ac_cv_header_nss_h"=20=3D=20xyes;=20then=20:=0A+=0A+else=0A= +=20=20as_fn_error=20$?=20"header=20file=20=20is=20required=20for=20= NSS"=20"$LINENO"=205=0A+fi=0A+=0A+=0A=20fi=0A=20=0A=20if=20test=20= "$with_pam"=20=3D=20yes=20;=20then=0A@@=20-14588,7=20+14811,7=20@@=20= else=0A=20=20=20=20=20We=20can't=20simply=20define=20LARGE_OFF_T=20to=20= be=209223372036854775807,=0A=20=20=20=20=20since=20some=20C++=20= compilers=20masquerading=20as=20C=20compilers=0A=20=20=20=20=20= incorrectly=20reject=209223372036854775807.=20=20*/=0A-#define=20= LARGE_OFF_T=20(((off_t)=201=20<<=2062)=20-=201=20+=20((off_t)=201=20<<=20= 62))=0A+#define=20LARGE_OFF_T=20((((off_t)=201=20<<=2031)=20<<=2031)=20-=20= 1=20+=20(((off_t)=201=20<<=2031)=20<<=2031))=0A=20=20=20int=20= off_t_is_large[(LARGE_OFF_T=20%=202147483629=20=3D=3D=20721=0A=20=09=09=20= =20=20=20=20=20=20&&=20LARGE_OFF_T=20%=202147483647=20=3D=3D=201)=0A=20=09= =09=20=20=20=20=20=20?=201=20:=20-1];=0A@@=20-14634,7=20+14857,7=20@@=20= else=0A=20=20=20=20=20We=20can't=20simply=20define=20LARGE_OFF_T=20to=20= be=209223372036854775807,=0A=20=20=20=20=20since=20some=20C++=20= compilers=20masquerading=20as=20C=20compilers=0A=20=20=20=20=20= incorrectly=20reject=209223372036854775807.=20=20*/=0A-#define=20= LARGE_OFF_T=20(((off_t)=201=20<<=2062)=20-=201=20+=20((off_t)=201=20<<=20= 62))=0A+#define=20LARGE_OFF_T=20((((off_t)=201=20<<=2031)=20<<=2031)=20-=20= 1=20+=20(((off_t)=201=20<<=2031)=20<<=2031))=0A=20=20=20int=20= off_t_is_large[(LARGE_OFF_T=20%=202147483629=20=3D=3D=20721=0A=20=09=09=20= =20=20=20=20=20=20&&=20LARGE_OFF_T=20%=202147483647=20=3D=3D=201)=0A=20=09= =09=20=20=20=20=20=20?=201=20:=20-1];=0A@@=20-14658,7=20+14881,7=20@@=20= rm=20-f=20core=20conftest.err=20conftest.$ac_objext=20conftest.$ac_ext=0A= =20=20=20=20=20We=20can't=20simply=20define=20LARGE_OFF_T=20to=20be=20= 9223372036854775807,=0A=20=20=20=20=20since=20some=20C++=20compilers=20= masquerading=20as=20C=20compilers=0A=20=20=20=20=20incorrectly=20reject=20= 9223372036854775807.=20=20*/=0A-#define=20LARGE_OFF_T=20(((off_t)=201=20= <<=2062)=20-=201=20+=20((off_t)=201=20<<=2062))=0A+#define=20LARGE_OFF_T=20= ((((off_t)=201=20<<=2031)=20<<=2031)=20-=201=20+=20(((off_t)=201=20<<=20= 31)=20<<=2031))=0A=20=20=20int=20off_t_is_large[(LARGE_OFF_T=20%=20= 2147483629=20=3D=3D=20721=0A=20=09=09=20=20=20=20=20=20=20&&=20= LARGE_OFF_T=20%=202147483647=20=3D=3D=201)=0A=20=09=09=20=20=20=20=20=20= ?=201=20:=20-1];=0A@@=20-14703,7=20+14926,7=20@@=20else=0A=20=20=20=20=20= We=20can't=20simply=20define=20LARGE_OFF_T=20to=20be=20= 9223372036854775807,=0A=20=20=20=20=20since=20some=20C++=20compilers=20= masquerading=20as=20C=20compilers=0A=20=20=20=20=20incorrectly=20reject=20= 9223372036854775807.=20=20*/=0A-#define=20LARGE_OFF_T=20(((off_t)=201=20= <<=2062)=20-=201=20+=20((off_t)=201=20<<=2062))=0A+#define=20LARGE_OFF_T=20= ((((off_t)=201=20<<=2031)=20<<=2031)=20-=201=20+=20(((off_t)=201=20<<=20= 31)=20<<=2031))=0A=20=20=20int=20off_t_is_large[(LARGE_OFF_T=20%=20= 2147483629=20=3D=3D=20721=0A=20=09=09=20=20=20=20=20=20=20&&=20= LARGE_OFF_T=20%=202147483647=20=3D=3D=201)=0A=20=09=09=20=20=20=20=20=20= ?=201=20:=20-1];=0A@@=20-14727,7=20+14950,7=20@@=20rm=20-f=20core=20= conftest.err=20conftest.$ac_objext=20conftest.$ac_ext=0A=20=20=20=20=20= We=20can't=20simply=20define=20LARGE_OFF_T=20to=20be=20= 9223372036854775807,=0A=20=20=20=20=20since=20some=20C++=20compilers=20= masquerading=20as=20C=20compilers=0A=20=20=20=20=20incorrectly=20reject=20= 9223372036854775807.=20=20*/=0A-#define=20LARGE_OFF_T=20(((off_t)=201=20= <<=2062)=20-=201=20+=20((off_t)=201=20<<=2062))=0A+#define=20LARGE_OFF_T=20= ((((off_t)=201=20<<=2031)=20<<=2031)=20-=201=20+=20(((off_t)=201=20<<=20= 31)=20<<=2031))=0A=20=20=20int=20off_t_is_large[(LARGE_OFF_T=20%=20= 2147483629=20=3D=3D=20721=0A=20=09=09=20=20=20=20=20=20=20&&=20= LARGE_OFF_T=20%=202147483647=20=3D=3D=201)=0A=20=09=09=20=20=20=20=20=20= ?=201=20:=20-1];=0Adiff=20--git=20a/configure.in=20b/configure.in=0A= index=200188c6ff07..afa90f7fbc=20100644=0A---=20a/configure.in=0A+++=20= b/configure.in=0A@@=20-854,6=20+854,15=20@@=20PGAC_ARG_BOOL(with,=20= openssl,=20no,=20[build=20with=20OpenSSL=20support],=0A=20= AC_MSG_RESULT([$with_openssl])=0A=20AC_SUBST(with_openssl)=0A=20=0A+#=0A= +#=20LibNSS=0A+#=0A+AC_MSG_CHECKING([whether=20to=20build=20with=20NSS=20= support])=0A+PGAC_ARG_BOOL(with,=20nss,=20no,=20[build=20with=20NSS=20= support],=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20= [AC_DEFINE([USE_NSS],=201,=20[Define=20to=20build=20with=20NSS=20= support.=20(--with-nss)])])=0A+AC_MSG_RESULT([$with_nss])=0A= +AC_SUBST(with_nss)=0A+=0A=20#=0A=20#=20SELinux=0A=20#=0A@@=20-1203,6=20= +1212,9=20@@=20if=20test=20"$with_gssapi"=20=3D=20yes=20;=20then=0A=20fi=0A= =20=0A=20if=20test=20"$with_openssl"=20=3D=20yes=20;=20then=0A+=20=20if=20= test=20x"$with_nss"=20=3D=20x"yes"=20;=20then=0A+=20=20=20=20= AC_MSG_ERROR([multiple=20SSL=20backends=20cannot=20be=20enabled=20= simultaneously"])=0A+=20=20fi=0A=20=20=20dnl=20Order=20matters!=0A=20=20=20= if=20test=20"$PORTNAME"=20!=3D=20"win32";=20then=0A=20=20=20=20=20=20= AC_CHECK_LIB(crypto,=20CRYPTO_new_ex_data,=20[],=20= [AC_MSG_ERROR([library=20'crypto'=20is=20required=20for=20OpenSSL])])=0A= @@=20-1225,6=20+1237,19=20@@=20if=20test=20"$with_openssl"=20=3D=20yes=20= ;=20then=0A=20=20=20AC_CHECK_FUNCS([CRYPTO_lock])=0A=20fi=0A=20=0A+if=20= test=20"$with_nss"=20=3D=20yes=20;=20then=0A+=20=20if=20test=20= x"$with_openssl"=20=3D=20x"yes"=20;=20then=0A+=20=20=20=20= AC_MSG_ERROR([multiple=20SSL=20backends=20cannot=20be=20enabled=20= simultaneously"])=0A+=20=20fi=0A+=20=20CLEANLDFLAGS=3D"$LDFLAGS"=0A+=20=20= #=20TODO:=20document=20this=20set=20of=20LDFLAGS=0A+=20=20= LDFLAGS=3D"-lssl3=20-lsmime3=20-lnss3=20-lplds4=20-lplc4=20-lnspr4=20= $LDFLAGS"=0A+=20=20AC_CHECK_LIB(nss3,=20SSL_VersionRangeSet,=20[],=20= [AC_MSG_ERROR([library=20'nss3'=20is=20required=20for=20NSS])])=0A+=20=20= AC_CHECK_LIB(nspr4,=20PR_GetDefaultIOMethods,=20[],=20= [AC_MSG_ERROR([library=20'nspr4'=20is=20required=20for=20NSS])])=0A+=20=20= AC_CHECK_LIB(ssl3,=20SSL_GetImplementedCiphers,=20[],=20= [AC_MSG_ERROR([library=20'ssl3'=20is=20required=20for=20NSS])])=0A+=20=20= LDFLAGS=3D"$CLEANLDFLAGS"=0A+fi=0A+=0A=20if=20test=20"$with_pam"=20=3D=20= yes=20;=20then=0A=20=20=20AC_CHECK_LIB(pam,=20=20=20=20pam_start,=20[],=20= [AC_MSG_ERROR([library=20'pam'=20is=20required=20for=20PAM])])=0A=20fi=0A= @@=20-1400,6=20+1425,11=20@@=20if=20test=20"$with_openssl"=20=3D=20yes=20= ;=20then=0A=20=20=20AC_CHECK_HEADER(openssl/err.h,=20[],=20= [AC_MSG_ERROR([header=20file=20=20is=20required=20for=20= OpenSSL])])=0A=20fi=0A=20=0A+if=20test=20"$with_nss"=20=3D=20yes=20;=20= then=0A+=20=20AC_CHECK_HEADER(ssl.h,=20[],=20[AC_MSG_ERROR([header=20= file=20=20is=20required=20for=20NSS])])=0A+=20=20= AC_CHECK_HEADER(nss.h,=20[],=20[AC_MSG_ERROR([header=20file=20=20= is=20required=20for=20NSS])])=0A+fi=0A+=0A=20if=20test=20"$with_pam"=20=3D= =20yes=20;=20then=0A=20=20=20AC_CHECK_HEADERS(security/pam_appl.h,=20[],=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= [AC_CHECK_HEADERS(pam/pam_appl.h,=20[],=0Adiff=20--git=20= a/src/Makefile.global.in=20b/src/Makefile.global.in=0Aindex=20= 9a6265b3a0..1f1706c4d0=20100644=0A---=20a/src/Makefile.global.in=0A+++=20= b/src/Makefile.global.in=0A@@=20-184,6=20+184,7=20@@=20with_perl=09=3D=20= @with_perl@=0A=20with_python=09=3D=20@with_python@=0A=20with_tcl=09=3D=20= @with_tcl@=0A=20with_openssl=09=3D=20@with_openssl@=0A+with_nss=20=20=20=20= =20=20=20=20=3D=20@with_nss@=0A=20with_readline=09=3D=20@with_readline@=0A= =20with_selinux=09=3D=20@with_selinux@=0A=20with_systemd=09=3D=20= @with_systemd@=0Adiff=20--git=20a/src/backend/libpq/Makefile=20= b/src/backend/libpq/Makefile=0Aindex=20efc5ef760a..191266a426=20100644=0A= ---=20a/src/backend/libpq/Makefile=0A+++=20b/src/backend/libpq/Makefile=0A= @@=20-30,6=20+30,10=20@@=20OBJS=20=3D=20\=0A=20=0A=20ifeq=20= ($(with_openssl),yes)=0A=20OBJS=20+=3D=20be-secure-openssl.o=0A+else=0A= +ifeq=20($(with_nss),yes)=0A+OBJS=20+=3D=20be-secure-nss.o=0A+endif=0A=20= endif=0A=20=0A=20ifeq=20($(with_gssapi),yes)=0Adiff=20--git=20= a/src/backend/libpq/auth.c=20b/src/backend/libpq/auth.c=0Aindex=20= 02b6c3f127..8f4197d002=20100644=0A---=20a/src/backend/libpq/auth.c=0A+++=20= b/src/backend/libpq/auth.c=0A@@=20-2870,7=20+2870,14=20@@=20= CheckCertAuth(Port=20*port)=0A=20{=0A=20=09int=09=09=09= status_check_usermap=20=3D=20STATUS_ERROR;=0A=20=0A+#if=20= defined(USE_OPENSSL)=0A=20=09Assert(port->ssl);=0A+#elif=20= defined(USE_NSS)=0A+=09/*=20TODO:=20should=20we=20rename=20pr_fd=20to=20= ssl,=20to=20keep=20consistency?=20*/=0A+=09Assert(port->pr_fd);=0A+#else=0A= +=09Assert(false);=0A+#endif=0A=20=0A=20=09/*=20Make=20sure=20we=20have=20= received=20a=20username=20in=20the=20certificate=20*/=0A=20=09if=20= (port->peer_cn=20=3D=3D=20NULL=20||=0Adiff=20--git=20= a/src/backend/libpq/be-secure-nss.c=20= b/src/backend/libpq/be-secure-nss.c=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..07df6c2752=0A---=20/dev/null=0A+++=20= b/src/backend/libpq/be-secure-nss.c=0A@@=20-0,0=20+1,1026=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20be-secure-nss.c=0A+=20*=09=20=20functions=20for=20= supporting=20NSS=20as=20a=20TLS=20backend=0A+=20*=0A+=20*=0A+=20*=20= Portions=20Copyright=20(c)=201996-2020,=20PostgreSQL=20Global=20= Development=20Group=0A+=20*=20Portions=20Copyright=20(c)=201994,=20= Regents=20of=20the=20University=20of=20California=0A+=20*=0A+=20*=20= IDENTIFICATION=0A+=20*=09=20=20src/backend/libpq/be-secure-nss.c=0A+=20*=0A= +=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+=0A+#include=20"postgres.h"=0A+=0A+#include=20=0A= +=0A+/*=0A+=20*=20BITS_PER_BYTE=20is=20also=20defined=20in=20the=20NSPR=20= header=20fils,=20so=20we=20need=20to=20undef=0A+=20*=20our=20version=20= to=20avoid=20compiler=20warnings=20on=20redefinition.=0A+=20*/=0A= +#define=20pg_BITS_PER_BYTE=20BITS_PER_BYTE=0A+#undef=20BITS_PER_BYTE=0A= +=0A+/*=0A+=20*=20The=20nspr/obsolete/protypes.h=20NSPR=20header=20= typedefs=20uint64=20and=20int64=20with=0A+=20*=20colliding=20definitions=20= from=20ours,=20causing=20a=20much=20expected=20compiler=20error.=0A+=20*=20= The=20definitions=20are=20however=20not=20actually=20used=20in=20NSPR=20= at=20all,=20and=20are=20only=0A+=20*=20intended=20for=20what=20seems=20= to=20be=20backwards=20compatibility=20for=20apps=20written=0A+=20*=20= against=20old=20versions=20of=20NSPR.=20=20The=20following=20comment=20= is=20in=20the=20referenced=0A+=20*=20file,=20and=20was=20added=20in=20= 1998:=0A+=20*=0A+=20*=09=09This=20section=20typedefs=20the=20old=20= 'native'=20types=20to=20the=20new=20PRs.=0A+=20*=09=09These=20= definitions=20are=20scheduled=20to=20be=20eliminated=20at=20the=20= earliest=0A+=20*=09=09possible=20time.=20The=20NSPR=20API=20is=20= implemented=20and=20documented=20using=0A+=20*=09=09the=20new=20= definitions.=0A+=20*=0A+=20*=20As=20there=20is=20no=20opt-out=20from=20= pulling=20in=20these=20typedefs,=20we=20define=20the=20guard=0A+=20*=20= for=20the=20file=20to=20exclude=20it.=20This=20is=20incredibly=20ugly,=20= but=20seems=20to=20be=20about=0A+=20*=20the=20only=20way=20around=20it.=0A= +=20*/=0A+#define=20PROTYPES_H=0A+#include=20=0A+#undef=20= PROTYPES_H=0A+#include=20=0A+#include=20=0A+#include=20= =0A+#include=20=0A+#include=20=0A+#include=20= =0A+#include=20=0A+#include=20=0A= +#include=20=0A+#include=20=0A+#include=20= =0A+#include=20=0A+#include=20=0A+#include=20= =0A+#include=20=0A+#include=20=0A+=0A= +typedef=20struct=0A+{=0A+=09enum=0A+=09{=0A+=09=09PW_NONE=20=3D=200,=0A= +=09=09PW_FROMFILE=20=3D=201,=0A+=09=09PW_PLAINTEXT=20=3D=202,=0A+=09=09= PW_EXTERNAL=20=3D=203=0A+=09}=20source;=0A+=09char=20*data;=0A+}=20= secuPWData;=0A+=0A+/*=0A+=20*=20Ensure=20that=20the=20colliding=20= definitions=20match,=20else=20throw=20an=20error.=20In=20case=0A+=20*=20= NSPR=20has=20removed=20the=20definition=20for=20some=20reasone,=20make=20= sure=20to=20put=20ours=0A+=20*=20back=20again.=0A+=20*/=0A+#if=20= defined(BITS_PER_BYTE)=0A+#=20=20if=20BITS_PER_BYTE=20!=3D=20= pg_BITS_PER_BYTE=0A+#=20=20=20=20error=20"incompatible=20byte=20widths=20= between=20NSPR=20and=20postgres"=0A+#=20=20endif=0A+#else=0A+#=20=20= define=20BITS_PER_BYTE=20pg_BITS_PER_BYTE=0A+#endif=0A+#undef=20= pg_BITS_PER_BYTE=0A+=0A+#include=20"common/pg_nss.h"=0A+#include=20= "lib/stringinfo.h"=0A+#include=20"libpq/libpq.h"=0A+#include=20= "nodes/pg_list.h"=0A+#include=20"miscadmin.h"=0A+#include=20= "storage/fd.h"=0A+#include=20"utils/guc.h"=0A+#include=20= "utils/memutils.h"=0A+=0A+static=20PRDescIdentity=20pr_id;=0A+=0A+static=20= PRIOMethods=09=09=09=09pr_iomethods;=0A+static=20NSSInitContext=09=09=20=20= =20*nss_context=20=3D=20NULL;=0A+static=20SSLVersionRange=09=09=09= desired_sslver;=0A+=0A+/*=0A+=20*=20PR_ImportTCPSocket()=20is=20a=20= private=20API,=20but=20very=20widely=20used,=20as=20it's=20the=0A+=20*=20= only=20way=20to=20make=20NSS=20use=20an=20already=20set=20up=20POSIX=20= file=20descriptor=20rather=0A+=20*=20than=20opening=20one=20itself.=20To=20= quote=20the=20NSS=20documentation:=0A+=20*=0A+=20*=09=09"In=20theory,=20= code=20that=20uses=20PR_ImportTCPSocket=20may=20break=20when=20NSPR's=0A= +=20*=09=09implementation=20changes.=20In=20practice,=20this=20is=20= unlikely=20to=20happen=20because=0A+=20*=09=09NSPR's=20implementation=20= has=20been=20stable=20for=20years=20and=20because=20of=20NSPR's=0A+=20*=09= =09strong=20commitment=20to=20backward=20compatibility."=0A+=20*=0A+=20*=20= https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/P= R_ImportTCPSocket=0A+=20*=0A+=20*=20The=20function=20is=20declared=20in=20= ,=20but=20as=20it=20is=20a=20header=20marked=0A+=20*=20= private=20we=20declare=20it=20here=20rather=20than=20including=20it.=0A+=20= */=0A+NSPR_API(PRFileDesc*)=20PR_ImportTCPSocket(int);=0A+=0A+/*=20NSS=20= IO=20layer=20callback=20overrides=20*/=0A+static=20PRInt32=20= pg_ssl_read(PRFileDesc=20*fd,=20void=20*buf,=20PRInt32=20amount,=0A+=09=09= =09=09=09=09=20=20=20PRIntn=20flags,=20PRIntervalTime=20timeout);=0A= +static=20PRInt32=20pg_ssl_write(PRFileDesc=20*fd,=20const=20void=20= *buf,=20PRInt32=20amount,=0A+=09=09=09=09=09=09=09PRIntn=20flags,=20= PRIntervalTime=20timeout);=0A+/*=20Utility=20functions=20*/=0A+static=20= PRFileDesc=20*init_iolayer(Port=20*port,=20int=20loglevel);=0A+static=20= uint16=20ssl_protocol_version_to_nss(int=20v,=20const=20char=20= *guc_name);=0A+=0A+static=20char=20*pg_SSLerrmessage(PRErrorCode=20= errcode);=0A+static=20char=20*ssl_protocol_version_to_string(int=20v);=0A= +static=20SECStatus=20pg_cert_auth_handler(void=20*arg,=20PRFileDesc=20= *fd,=0A+=09=09=09PRBool=20checksig,=20PRBool=20isServer);=0A+static=20= SECStatus=20pg_bad_cert_handler(void=20*arg,=20PRFileDesc=20*fd);=0A+=0A= +/*=20------------------------------------------------------------=20*/=0A= +/*=09=09=09=09=09=09=20Public=20interface=09=09=09=09=09=09*/=0A+/*=20= ------------------------------------------------------------=20*/=0A+=0A= +static=20char=20*=0A+ssl_passphrase_callback(PK11SlotInfo=20*slot,=20= PRBool=20retry,=20void=20*arg)=0A+{=0A+=09return=20pstrdup("");=0A+}=0A+=0A= +/*=0A+=20*=20be_tls_init=0A+=20*=09=09=09Initialize=20the=20nss=20TLS=20= library=20in=20the=20postmaster=0A+=20*=0A+=20*=20The=20majority=20of=20= the=20setup=20needs=20to=20happen=20in=20be_tls_open_server=20since=20= the=0A+=20*=20NSPR=20initialization=20must=20happen=20after=20the=20= forking=20of=20the=20backend.=20We=20could=0A+=20*=20potentially=20move=20= some=20parts=20in=20under=20!isServerStart,=20but=20so=20far=20this=20is=20= the=0A+=20*=20separation=20chosen.=0A+=20*/=0A+int=0A+be_tls_init(bool=20= isServerStart)=0A+{=0A+=09SECStatus=09=09=09status;=0A+=09= SSLVersionRange=09=09supported_sslver;=0A+=0A+=09/*=0A+=09=20*=20Set=20= up=20the=20connection=20cache=20for=20multi-processing=20application=20= behavior.=0A+=09=20*=20If=20we=20are=20in=20ServerStart=20then=20we=20= initialize=20the=20cache.=20If=20the=20server=20is=0A+=09=20*=20already=20= started,=20we=20inherit=20the=20cache=20such=20that=20it=20can=20be=20= used=20for=0A+=09=20*=20connections.=20Calling=20= SSL_ConfigMPServerSIDCache=20sets=20an=20environment=0A+=09=20*=20= variable=20which=20contains=20enough=20information=20for=20the=20forked=20= child=20to=20know=0A+=09=20*=20how=20to=20access=20it.=20=20Passing=20= NULL=20to=20SSL_InheritMPServerSIDCache=20will=20make=0A+=09=20*=20the=20= forked=20child=20look=20it=20up=20by=20the=20default=20name=20= SSL_INHERITANCE,=20if=20env=0A+=09=20*=20vars=20aren't=20inherited=20= then=20the=20contents=20of=20the=20variable=20can=20be=20passed=0A+=09=20= *=20instead.=0A+=09=20*/=0A+=09if=20(isServerStart)=0A+=09{=0A+=09=09/*=0A= +=09=09=20*=20SSLv2=20and=20SSLv3=20are=20disabled=20in=20this=20TLS=20= backend,=20but=20when=20setting=0A+=09=09=20*=20up=20the=20required=20= session=20cache=20for=20NSS=20we=20still=20must=20supply=20timeout=0A+=09= =09=20*=20values=20for=20v2=20and=20The=20minimum=20allowed=20value=20= for=20both=20is=205=0A+=09=09=20*=20seconds,=20so=20opt=20for=20that=20= in=20both=20cases=20(the=20defaults=20being=20100=0A+=09=09=20*=20= seconds=20and=2024=20hours).=0A+=09=09=20*=0A+=09=09=20*=20Passing=20= NULL=20as=20the=20directory=20for=20the=20session=20cache=20will=20= default=20to=0A+=09=09=20*=20using=20/tmp=20on=20UNIX=20and=20\\temp=20= on=20Windows.=20=20Deciding=20if=20we=20want=20to=0A+=09=09=20*=20keep=20= closer=20control=20on=20this=20directory=20is=20left=20as=20a=20TODO.=0A= +=09=09=20*/=0A+=09=09status=20=3D=20= SSL_ConfigMPServerSIDCache(MaxConnections,=205,=205,=20NULL);=0A+=09=09= if=20(status=20!=3D=20SECSuccess)=0A+=09=09=09ereport(FATAL,=0A+=09=09=09= =09=09(errmsg("unable=20to=20set=20up=20TLS=20connection=20cache:=20%s",=0A= +=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09}=0A= +=09else=0A+=09{=0A+=09=09status=20=3D=20= SSL_InheritMPServerSIDCache(NULL);=0A+=09=09if=20(status=20!=3D=20= SECSuccess)=0A+=09=09{=0A+=09=09=09ereport(LOG,=0A+=09=09=09=09=09= (errmsg("unable=20to=20connect=20to=20TLS=20connection=20cache:=20%s",=0A= +=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A+=09=09=09= return=20-1;=0A+=09=09}=0A+=09}=0A+=0A+=09if=20(!ssl_database=20||=20= strlen(ssl_database)=20=3D=3D=200)=0A+=09{=0A+=09=09= ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09=09=09=09(errmsg("no=20= certificate=20database=20specified")));=0A+=09=09goto=20error;=0A+=09}=0A= +=0A+=09/*=0A+=09=20*=20We=20check=20for=20the=20desired=20TLS=20version=20= range=20here,=20even=20though=20we=20cannot=0A+=09=20*=20set=20it=20= until=20be_open_server=20such=20that=20we=20can=20be=20compatible=20with=20= how=20the=0A+=09=20*=20OpenSSL=20backend=20reports=20errors=20for=20= incompatible=20range=20configurations.=0A+=09=20*=20Set=20either=20the=20= default=20supported=20TLS=20version=20range,=20or=20the=20configured=0A+=09= =20*=20range=20from=20ssl_min_protocol_version=20and=20ssl_max_protocol=20= version.=20In=0A+=09=20*=20case=20the=20user=20hasn't=20defined=20the=20= maximum=20allowed=20version=20we=20fall=20back=0A+=09=20*=20to=20the=20= highest=20version=20TLS=20that=20the=20library=20supports.=0A+=09=20*/=0A= +=09if=20(SSL_VersionRangeGetSupported(ssl_variant_stream,=20= &supported_sslver)=20!=3D=20SECSuccess)=0A+=09{=0A+=09=09= ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09=09=09=09= (errmsg("unable=20to=20get=20default=20protocol=20support=20from=20= NSS")));=0A+=09=09goto=20error;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Set=20= the=20fallback=20versions=20for=20the=20TLS=20protocol=20version=20range=20= to=20a=0A+=09=20*=20combination=20of=20our=20minimal=20requirement=20and=20= the=20library=20maximum.=0A+=09=20*/=0A+=09desired_sslver.min=20=3D=20= SSL_LIBRARY_VERSION_TLS_1_0;=0A+=09desired_sslver.max=20=3D=20= supported_sslver.max;=0A+=0A+=09if=20(ssl_min_protocol_version)=0A+=09{=0A= +=09=09int=20ver=20=3D=20= ssl_protocol_version_to_nss(ssl_min_protocol_version,=0A+=09=09=09=09=09=09= =09=09=09=09=09=20=20"ssl_min_protocol_version");=0A+=09=09if=20(ver=20= =3D=3D=20-1)=0A+=09=09{=0A+=09=09=09ereport(isServerStart=20?=20FATAL=20= :=20LOG,=0A+=09=09=09=09=09(errmsg("\"%s\"=20setting=20\"%s\"=20not=20= supported=20by=20this=20build",=0A+=09=09=09=09=09=09=09= "ssl_min_protocol_version",=0A+=09=09=09=09=09=09=09= GetConfigOption("ssl_min_protocol_version",=0A+=09=09=09=09=09=09=09=09=09= =09=09false,=20false))));=0A+=09=09=09goto=20error;=0A+=09=09}=0A+=0A+=09= =09if=20(ver=20>=200)=0A+=09=09=09desired_sslver.min=20=3D=20ver;=0A+=09= }=0A+=0A+=09if=20(ssl_max_protocol_version)=0A+=09{=0A+=09=09int=20ver=20= =3D=20ssl_protocol_version_to_nss(ssl_max_protocol_version,=0A+=09=09=09=09= =09=09=09=09=09=09=09=20=20"ssl_max_protocol_version");=0A+=09=09if=20= (ver=20=3D=3D=20-1)=0A+=09=09{=0A+=09=09=09ereport(isServerStart=20?=20= FATAL=20:=20LOG,=0A+=09=09=09=09=09(errmsg("\"%s\"=20setting=20\"%s\"=20= not=20supported=20by=20this=20build",=0A+=09=09=09=09=09=09=09= "ssl_max_protocol_version",=0A+=09=09=09=09=09=09=09= GetConfigOption("ssl_max_protocol_version",=0A+=09=09=09=09=09=09=09=09=09= =09=09false,=20false))));=0A+=09=09=09goto=20error;=0A+=09=09}=0A+=09=09= if=20(ver=20>=200)=0A+=09=09=09desired_sslver.max=20=3D=20ver;=0A+=0A+=09= =09if=20(ver=20<=20desired_sslver.min)=0A+=09=09{=0A+=09=09=09= ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09=09=09=09=09= (errmsg("could=20not=20set=20SSL=20protocol=20version=20range"),=0A+=09=09= =09=09=09=20errdetail("\"%s\"=20cannot=20be=20higher=20than=20\"%s\"",=0A= +=09=09=09=09=09=09=09=20=20=20"ssl_min_protocol_version",=0A+=09=09=09=09= =09=09=09=20=20=20"ssl_max_protocol_version")));=0A+=09=09=09goto=20= error;=0A+=09=09}=0A+=09}=0A+=0A+=09return=200;=0A+error:=0A+=09return=20= -1;=0A+}=0A+=0A+int=0A+be_tls_open_server(Port=20*port)=0A+{=0A+=09= SECStatus=09=09=09status;=0A+=09PRFileDesc=09=09=20=20=20*model;=0A+=09= PRFileDesc=09=09=20=20=20*pr_fd;=0A+=09PRFileDesc=09=09=20=20=20*layer;=0A= +=09CERTCertificate=09=20=20=20*server_cert;=0A+=09SECKEYPrivateKey=20=20= =20*private_key;=0A+=09CERTSignedCrl=09=20=20=20*crl;=0A+=09SECItem=09=09= =09=09crlname;=0A+=09secuPWData=20pwdata=20=3D=20{=20PW_NONE,=200=20};=09= =09/*=20TODO:=20This=20is=20a=20bogus=20callback=20*/=0A+=09char=09=09=09= =20=20=20*cert_database;=0A+=09NSSInitParameters=09params;=0A+=0A+=09/*=0A= +=09=20*=20The=20NSPR=20documentation=20states=20that=20runtime=20= initialization=20via=20PR_Init=20is=0A+=09=20*=20no=20longer=20required,=20= as=20the=20first=20caller=20into=20NSPR=20will=20perform=20the=0A+=09=20= *=20initialization=20implicitly.=20The=20documentation=20doesn't=20= however=20clarify=0A+=09=20*=20from=20which=20version=20this=20is=20= holds=20true,=20so=20let's=20perform=20the=20potentially=0A+=09=20*=20= superfluous=20initialization=20anyways=20to=20avoid=20crashing=20on=20= older=20versions=0A+=09=20*=20of=20NSPR,=20as=20there=20is=20no=20= difference=20in=20overhead.=20=20The=20NSS=20documentation=0A+=09=20*=20= still=20states=20that=20PR_Init=20must=20be=20called=20in=20some=20way=20= (implicitly=20or=0A+=09=20*=20explicitly).=0A+=09=20*=0A+=09=20*=20The=20= below=20parameters=20are=20what=20the=20implicit=20initialization=20= would've=20done=0A+=09=20*=20for=20us,=20and=20should=20work=20even=20= for=20older=20versions=20where=20it=20might=20not=20be=0A+=09=20*=20done=20= automatically.=20The=20last=20parameter,=20maxPTDs,=20is=20set=20to=20= various=0A+=09=20*=20values=20in=20other=20codebases,=20but=20has=20been=20= unused=20since=20NSPR=202.1=20which=20was=0A+=09=20*=20released=20= sometime=20in=201998.=0A+=09=20*/=0A+=09PR_Init(PR_USER_THREAD,=20= PR_PRIORITY_NORMAL,=200=20/*=20maxPTDs=20*/);=0A+=0A+=09/*=0A+=09=20*=20= The=20certificate=20path=20(configdir)=20must=20contain=20a=20valid=20= NSS=20database.=0A+=09=20*=20If=20the=20certificate=20path=20isn't=20a=20= valid=20directory,=20NSS=20will=20fall=20back=20on=0A+=09=20*=20the=20= system=20certificate=20database.=20If=20the=20certificate=20path=20is=20= a=20directory=0A+=09=20*=20but=20is=20empty=20then=20the=20= initialization=20will=20fail.=20On=20the=20client=20side=20this=0A+=09=20= *=20can=20be=20allowed=20for=20any=20sslmode=20but=20the=20verify-xxx=20= ones.=0A+=09=20*=20https://bugzilla.redhat.com/show_bug.cgi?id=3D728562=0A= +=09=20*=20For=20the=20server=20side=20we=20wont=20allow=20this=20to=20= fail=20however,=20as=20we=20require=0A+=09=20*=20the=20certificate=20and=20= key=20to=20exist.=0A+=09=20*=0A+=09=20*=20The=20original=20design=20of=20= NSS=20was=20for=20a=20single=20application=20to=20use=20a=20single=0A+=09= =20*=20copy=20of=20it,=20initialized=20with=20NSS_Initialize()=20which=20= isn't=20returning=20any=0A+=09=20*=20handle=20with=20which=20to=20refer=20= to=20NSS.=20NSS=20initialization=20and=20shutdown=20are=0A+=09=20*=20= global=20for=20the=20application,=20so=20a=20shutdown=20in=20another=20= NSS=20enabled=20library=0A+=09=20*=20would=20cause=20NSS=20to=20be=20= stopped=20for=20libpq=20as=20well.=20=20The=20fix=20has=20been=20to=0A+=09= =20*=20introduce=20NSS_InitContext=20which=20returns=20a=20context=20= handle=20to=20pass=20to=0A+=09=20*=20NSS_ShutdownContext.=20=20= NSS_InitContext=20was=20introduced=20in=20NSS=203.12,=20but=0A+=09=20*=20= the=20use=20of=20it=20is=20not=20very=20well=20documented.=0A+=09=20*=20= https://bugzilla.redhat.com/show_bug.cgi?id=3D738456=0A+=09=20*=0A+=09=20= *=20The=20InitParameters=20struct=20passed=20can=20be=20used=20to=20= override=20internal=20values=0A+=09=20*=20in=20NSS,=20but=20the=20usage=20= is=20not=20documented=20at=20all.=20When=20using=20NSS_Init=0A+=09=20*=20= initializations,=20the=20values=20are=20instead=20set=20via=20= PK11_Configure=20calls=20so=0A+=09=20*=20the=20PK11_Configure=20= documentation=20can=20be=20used=20to=20glean=20some=20details=20on=0A+=09= =20*=20these.=0A+=09=20*=0A+=09=20*=20= https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/PKCS11/Modul= e_Specs=0A+=09=20*/=0A+=09memset(¶ms,=20'\0',=20sizeof(params));=0A+=09= params.length=20=3D=20sizeof(params);=0A+=0A+=09if=20(!ssl_database=20||=20= strlen(ssl_database)=20=3D=3D=200)=0A+=09=09ereport(FATAL,=0A+=09=09=09=09= (errmsg("no=20certificate=20database=20specified")));=0A+=0A+=09= cert_database=20=3D=20psprintf("sql:%s",=20ssl_database);=0A+=09= nss_context=20=3D=20NSS_InitContext(cert_database,=20"",=20"",=20"",=0A+=09= =09=09=09=09=09=09=09=20=20¶ms,=0A+=09=09=09=09=09=09=09=09=20=20= NSS_INIT_READONLY=20|=20NSS_INIT_PK11RELOAD);=0A+=09= pfree(cert_database);=0A+=0A+=09if=20(!nss_context)=0A+=09=09= ereport(FATAL,=0A+=09=09=09=09(errmsg("unable=20to=20read=20certificate=20= database=20\"%s\":=20%s",=0A+=09=09=09=09=09=09ssl_database,=20= pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09/*=0A+=09=20*=20Set=20the=20= passphrase=20callback=20which=20will=20be=20used=20both=20to=20obtain=20= the=0A+=09=20*=20passphrase=20from=20the=20user,=20as=20well=20as=20by=20= NSS=20to=20obtain=20the=20phrase=0A+=09=20*=20repeatedly.=0A+=09=20*=0A+=09= =20*=20TODO:=20Figure=20this=20out=20-=20do=20note=20that=20we=20are=20= setting=20another=20password=0A+=09=20*=20callback=20below=20for=20= cert/key=20as=20well.=20Need=20to=20make=20sense=20of=20all=20these.=0A+=09= =20*/=0A+=09PK11_SetPasswordFunc(ssl_passphrase_callback);=0A+=0A+=09/*=0A= +=09=20*=20Import=20the=20already=20opened=20socket=20as=20we=20don't=20= want=20to=20use=20NSPR=20functions=0A+=09=20*=20for=20opening=20the=20= network=20socket=20due=20to=20how=20the=20PostgreSQL=20protocol=20works=0A= +=09=20*=20with=20TLS=20connections.=20This=20function=20is=20not=20part=20= of=20the=20NSPR=20public=20API,=0A+=09=20*=20see=20the=20comment=20at=20= the=20top=20of=20the=20file=20for=20the=20rationale=20of=20still=20using=0A= +=09=20*=20it.=0A+=09=20*/=0A+=09pr_fd=20=3D=20= PR_ImportTCPSocket(port->sock);=0A+=09if=20(!pr_fd)=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20connect=20to=20= socket")));=0A+=0A+=09/*=0A+=09=20*=20Most=20of=20the=20documentation=20= available,=20and=20implementations=20of,=20NSS/NSPR=0A+=09=20*=20use=20= the=20PR_NewTCPSocket()=20function=20here,=20which=20has=20the=20= drawback=20that=20it=0A+=09=20*=20can=20only=20create=20IPv4=20sockets.=20= Instead=20use=20PR_OpenTCPSocket()=20which=20copes=0A+=09=20*=20with=20= IPv6=20as=20well.=0A+=09=20*/=0A+=09model=20=3D=20= PR_OpenTCPSocket(port->laddr.addr.ss_family);=0A+=09if=20(!model)=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20open=20socket")));=0A= +=0A+=09/*=0A+=09=20*=20Convert=20the=20NSPR=20socket=20to=20an=20SSL=20= socket.=20Ensuring=20the=20success=20of=20this=0A+=09=20*=20operation=20= is=20critical=20as=20NSS=20SSL_*=20functions=20may=20return=20SECSuccess=20= on=0A+=09=20*=20the=20socket=20even=20though=20SSL=20hasn't=20been=20= enabled,=20which=20introduce=20a=20risk=0A+=09=20*=20of=20silent=20= downgrades.=0A+=09=20*/=0A+=09model=20=3D=20SSL_ImportFD(NULL,=20model);=0A= +=09if=20(!model)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20= to=20enable=20TLS=20on=20socket")));=0A+=0A+=09/*=0A+=09=20*=20Configure=20= basic=20settings=20for=20the=20connection=20over=20the=20SSL=20socket=20= in=0A+=09=20*=20order=20to=20set=20it=20up=20as=20a=20server.=0A+=09=20= */=0A+=09if=20(SSL_OptionSet(model,=20SSL_SECURITY,=20PR_TRUE)=20!=3D=20= SECSuccess)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20= configure=20TLS=20connection")));=0A+=0A+=09if=20(SSL_OptionSet(model,=20= SSL_HANDSHAKE_AS_SERVER,=20PR_TRUE)=20!=3D=20SECSuccess=20||=0A+=09=09= SSL_OptionSet(model,=20SSL_HANDSHAKE_AS_CLIENT,=20PR_FALSE)=20!=3D=20= SECSuccess)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20= configure=20TLS=20connection=20as=20server")));=0A+=0A+=09/*=0A+=09=20*=20= SSLv2=20is=20disabled=20by=20default,=20and=20SSLv3=20will=20be=20= excluded=20from=20the=20range=0A+=09=20*=20of=20allowed=20protocols=20= further=20down.=20Since=20we=20really=20don't=20want=20these=20to=0A+=09=20= *=20ever=20be=20enabled,=20let's=20use=20belts=20and=20suspenders=20and=20= explicitly=20turn=0A+=09=20*=20them=20off=20as=20well.=0A+=09=20*/=0A+=09= SSL_OptionSet(model,=20SSL_ENABLE_SSL2,=20PR_FALSE);=0A+=09= SSL_OptionSet(model,=20SSL_ENABLE_SSL3,=20PR_FALSE);=0A+=0A+#ifdef=20= SSL_CBC_RANDOM_IV=0A+=09/*=0A+=09=20*=20Enable=20protection=20against=20= the=20BEAST=20attack=20in=20case=20the=20NSS=20server=20has=0A+=09=20*=20= support=20for=20that.=20While=20SSLv3=20is=20disabled,=20we=20may=20= still=20allow=20TLSv1=0A+=09=20*=20which=20is=20affected.=20The=20option=20= isn't=20documented=20as=20an=20SSL=20option,=20but=20as=0A+=09=20*=20an=20= NSS=20environment=20variable.=0A+=09=20*/=0A+=09SSL_OptionSet(model,=20= SSL_CBC_RANDOM_IV,=20PR_TRUE);=0A+#endif=0A+=0A+=09/*=0A+=09=20*=20= Configure=20the=20allowed=20cipher.=20If=20there=20are=20no=20user=20= preferred=20suites,=20set=0A+=09=20*=20the=20domestic=20policy.=20TODO:=20= while=20this=20code=20works,=20the=20set=20of=20ciphers=0A+=09=20*=20= which=20can=20be=20set=20and=20still=20end=20up=20with=20a=20working=20= socket=20is=20woefully=0A+=09=20*=20underdocumented=20for=20anything=20= more=20recent=20than=20SSLv3=20(the=20code=20for=20TLS=0A+=09=20*=20= actually=20calls=20ssl3=20functions=20under=20the=20hood=20for=20= SSL_CipherPrefSet),=0A+=09=20*=20so=20it's=20unclear=20if=20this=20is=20= helpful=20or=20not.=20Using=20the=20policies=20works,=0A+=09=20*=20but=20= may=20be=20too=20coarsely=20grained.=0A+=09=20*=0A+=09=20*=20Another=20= TODO:=20The=20SSL_ImplementedCiphers=20table=20returned=20with=20calling=0A= +=09=20*=20SSL_GetImplementedCiphers=20is=20sorted=20in=20server=20= preference=20order.=20Sorting=0A+=09=20*=20SSLCipherSuites=20according=20= to=20the=20order=20of=20the=20ciphers=20therein=20could=20be=0A+=09=20*=20= a=20way=20to=20implement=20ssl_prefer_server_ciphers=20-=20if=20we=20at=20= all=20want=20to=20use=0A+=09=20*=20cipher=20selection=20for=20NSS=20like=20= how=20we=20do=20it=20for=20OpenSSL=20that=20is.=0A+=09=20*/=0A+=0A+=09/*=0A= +=09=20*=20If=20no=20ciphers=20are=20specified,=20we=20use=20the=20= domestic=20policy=0A+=09=20*/=0A+=09if=20(!SSLCipherSuites=20||=20= strlen(SSLCipherSuites)=20=3D=3D=200)=0A+=09{=0A+=09=09status=20=3D=20= NSS_SetDomesticPolicy();=0A+=09=09if=20(status=20!=3D=20SECSuccess)=0A+=09= =09=09ereport(ERROR,=0A+=09=09=09=09=09(errmsg("unable=20to=20set=20= cipher=20policy:=20%s",=0A+=09=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()))));=0A+=09}=0A+=09else=0A+=09{=0A+=09=09= char=09=09=20=20=20*ciphers,=20*c,=20*b;=0A+=09=09char=09=09=20=20=20= *sep=20=3D=20":;,=20";=0A+=09=09PRUint16=09=09ciphercode;=0A+=09=09const=20= PRUint16=20*nss_ciphers;=0A+=0A+=09=09/*=0A+=09=09=20*=20If=20the=20user=20= has=20specified=20a=20set=20of=20preferred=20cipher=20suites=20we=20= start=0A+=09=09=20*=20by=20turning=20off=20all=20the=20existing=20suites=20= to=20avoid=20the=20risk=20of=20down-=0A+=09=09=20*=20grades=20to=20a=20= weaker=20cipher=20than=20expected.=0A+=09=09=20*/=0A+=09=09nss_ciphers=20= =3D=20SSL_GetImplementedCiphers();=0A+=09=09for=20(int=20i=20=3D=200;=20= i=20<=20SSL_GetNumImplementedCiphers();=20i++)=0A+=09=09=09= SSL_CipherPrefSet(model,=20nss_ciphers[i],=20PR_FALSE);=0A+=0A+=09=09= ciphers=20=3D=20pstrdup(SSLCipherSuites);=0A+=0A+=09=09for=20(c=20=3D=20= strtok_r(ciphers,=20sep,=20&b);=20c;=20c=20=3D=20strtok_r(NULL,=20sep,=20= &b))=0A+=09=09{=0A+=09=09=09ciphercode=20=3D=20pg_find_cipher(c);=0A+=09=09= =09if=20(ciphercode=20!=3D=20INVALID_CIPHER)=0A+=09=09=09{=0A+=09=09=09=09= status=20=3D=20SSL_CipherPrefSet(model,=20ciphercode,=20PR_TRUE);=0A+=09=09= =09=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09=09=09=09ereport(ERROR,=0A= +=09=09=09=09=09=09=09(errmsg("invalid=20cipher-suite=20specified:=20= %s",=20c)));=0A+=09=09=09}=0A+=09=09}=0A+=0A+=09=09pfree(ciphers);=0A+=09= }=0A+=0A+=09if=20(SSL_VersionRangeSet(model,=20&desired_sslver)=20!=3D=20= SECSuccess)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20= set=20requested=20SSL=20protocol=20version=20range")));=0A+=0A+=09/*=0A+=09= =20*=20Set=20up=20the=20custom=20IO=20layer.=0A+=09=20*/=0A+=09layer=20=3D= =20init_iolayer(port,=20ERROR);=0A+=09if=20(!layer)=0A+=09=09goto=20= error;=0A+=0A+=09/*=20Store=20the=20Port=20as=20private=20data=20= available=20in=20callbacks=20*/=0A+=09layer->secret=20=3D=20(void=20*)=20= port;=0A+=0A+=09if=20(PR_PushIOLayer(pr_fd,=20PR_TOP_IO_LAYER,=20layer)=20= !=3D=20PR_SUCCESS)=0A+=09{=0A+=09=09PR_Close(layer);=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20push=20IO=20= layer")));=0A+=09}=0A+=0A+=09/*=20TODO:=20set=20the=20postgres=20= password=20callback=20param=20as=20callback=20function=20*/=0A+=09= server_cert=20=3D=20PK11_FindCertFromNickname(ssl_cert_file,=20&pwdata=20= /*=20password=20callback=20*/);=0A+=09if=20(!server_cert)=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20find=20certificate=20= for=20\"%s\":=20%s",=0A+=09=09=09=09=09=09ssl_cert_file,=20= pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09/*=20TODO:=20set=20the=20= postgres=20password=20callback=20param=20as=20callback=20function=20*/=0A= +=09private_key=20=3D=20PK11_FindKeyByAnyCert(server_cert,=20&pwdata=20= /*=20password=20callback=20*/);=0A+=09if=20(!private_key)=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20find=20private=20= key=20for=20\"%s\":=20%s",=0A+=09=09=09=09=09=09ssl_cert_file,=20= pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09/*=0A+=09=20*=20NSS=20= doesn't=20use=20CRL=20files=20on=20disk,=20so=20we=20use=20the=20= ssl_crl_file=20guc=20to=0A+=09=20*=20contain=20the=20CRL=20nickname=20= for=20the=20current=20server=20certificate=20in=20the=20NSS=0A+=09=20*=20= certificate=20database.=20The=20main=20difference=20from=20the=20OpenSSL=20= backend=20is=0A+=09=20*=20that=20NSS=20will=20use=20the=20CRL=20= regardless,=20but=20being=20able=20to=20make=20sure=20the=0A+=09=20*=20= CRL=20is=20loaded=20seems=20like=20a=20good=20feature.=0A+=09=20*/=0A+=09= if=20(ssl_crl_file[0])=0A+=09{=0A+=09=09SECITEM_CopyItem(NULL,=20= &crlname,=20&server_cert->derSubject);=0A+=09=09crl=20=3D=20= SEC_FindCrlByName(CERT_GetDefaultCertDB(),=20&crlname,=20SEC_CRL_TYPE);=0A= +=09=09if=20(!crl)=0A+=09=09=09ereport(ERROR,=0A+=09=09=09=09=09= (errmsg("specified=20CRL=20not=20found=20in=20database")));=0A+=09=09= SEC_DestroyCrl(crl);=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Finally=20we=20= must=20configure=20the=20socket=20for=20being=20a=20server=20by=20= setting=20the=0A+=09=20*=20certificate=20and=20key.=0A+=09=20*/=0A+=09= status=20=3D=20SSL_ConfigSecureServer(model,=20server_cert,=20= private_key,=20kt_rsa);=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09= ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20configure=20secure=20= server:=20%s",=0A+=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A= +=09status=20=3D=20SSL_ConfigServerCert(model,=20server_cert,=20= private_key,=20NULL,=200);=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09= =09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20configure=20= server=20for=20TLS=20server=20connections:=20%s",=0A+=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09= ssl_loaded_verify_locations=20=3D=20true;=0A+=0A+=09/*=0A+=09=20*=20At=20= this=20point,=20we=20no=20longer=20have=20use=20for=20the=20certificate=20= and=20private=0A+=09=20*=20key=20as=20they=20have=20been=20copied=20into=20= the=20context=20by=20NSS.=20Destroy=20our=0A+=09=20*=20copies=20= explicitly=20to=20clean=20out=20the=20memory=20as=20best=20we=20can.=0A+=09= =20*/=0A+=09CERT_DestroyCertificate(server_cert);=0A+=09= SECKEY_DestroyPrivateKey(private_key);=0A+=0A+=09status=20=3D=20= SSL_AuthCertificateHook(model,=20pg_cert_auth_handler,=20(void=20*)=20= port);=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09ereport(ERROR,=0A= +=09=09=09=09(errmsg("unable=20to=20install=20authcert=20hook:=20%s",=0A= +=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A+=09= SSL_BadCertHook(model,=20pg_bad_cert_handler,=20(void=20*)=20port);=0A+=09= SSL_OptionSet(model,=20SSL_REQUEST_CERTIFICATE,=20PR_TRUE);=0A+=09= SSL_OptionSet(model,=20SSL_REQUIRE_CERTIFICATE,=20PR_FALSE);=0A+=0A+=09= port->pr_fd=20=3D=20SSL_ImportFD(model,=20pr_fd);=0A+=09if=20= (!port->pr_fd)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20= to=20initialize")));=0A+=0A+=09PR_Close(model);=0A+=0A+=09/*=0A+=09=20*=20= Force=20a=20handshake=20on=20the=20next=20I/O=20request,=20the=20second=20= parameter=20means=0A+=09=20*=20that=20we=20are=20a=20server,=20PR_FALSE=20= would=20indicate=20being=20a=20client.=20NSPR=0A+=09=20*=20requires=20us=20= to=20call=20SSL_ResetHandshake=20since=20we=20imported=20an=20already=0A= +=09=20*=20established=20socket.=0A+=09=20*/=0A+=09status=20=3D=20= SSL_ResetHandshake(port->pr_fd,=20PR_TRUE);=0A+=09if=20(status=20!=3D=20= SECSuccess)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09(errmsg("unable=20to=20= initiate=20handshake:=20%s",=0A+=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()))));=0A+=09status=20=3D=20= SSL_ForceHandshake(port->pr_fd);=0A+=09if=20(status=20!=3D=20SECSuccess)=0A= +=09=09ereport(ERROR,=0A+=09=09=09(errmsg("unable=20to=20handshake:=20= %s",=0A+=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A+=0A+=09= port->ssl_in_use=20=3D=20true;=0A+=09return=200;=0A+=0A+error:=0A+=09= return=201;=0A+}=0A+=0A+ssize_t=0A+be_tls_read(Port=20*port,=20void=20= *ptr,=20size_t=20len,=20int=20*waitfor)=0A+{=0A+=09ssize_t=09=09=09= n_read;=0A+=09PRErrorCode=09=09err;=0A+=0A+=09n_read=20=3D=20= PR_Read(port->pr_fd,=20ptr,=20len);=0A+=0A+=09if=20(n_read=20<=200)=0A+=09= {=0A+=09=09err=20=3D=20PR_GetError();=0A+=0A+=09=09/*=20XXX:=20This=20= logic=20seems=20potentially=20bogus?=20*/=0A+=09=09if=20(err=20=3D=3D=20= PR_WOULD_BLOCK_ERROR)=0A+=09=09=09*waitfor=20=3D=20WL_SOCKET_READABLE;=0A= +=09=09else=0A+=09=09=09*waitfor=20=3D=20WL_SOCKET_WRITEABLE;=0A+=09}=0A= +=0A+=09return=20n_read;=0A+}=0A+=0A+ssize_t=0A+be_tls_write(Port=20= *port,=20void=20*ptr,=20size_t=20len,=20int=20*waitfor)=0A+{=0A+=09= ssize_t=09=09=09n_write;=0A+=09PRErrorCode=09=09err;=0A+=0A+=09n_write=20= =3D=20PR_Send(port->pr_fd,=20ptr,=20len,=200,=20PR_INTERVAL_NO_WAIT);=0A= +=0A+=09if=20(n_write=20<=200)=0A+=09{=0A+=09=09err=20=3D=20= PR_GetError();=0A+=0A+=09=09if=20(err=20=3D=3D=20PR_WOULD_BLOCK_ERROR)=0A= +=09=09=09*waitfor=20=3D=20WL_SOCKET_WRITEABLE;=0A+=09=09else=0A+=09=09=09= *waitfor=20=3D=20WL_SOCKET_READABLE;=0A+=09}=0A+=0A+=09return=20n_write;=0A= +}=0A+=0A+void=0A+be_tls_close(Port=20*port)=0A+{=0A+=09if=20(!port)=0A+=09= =09return;=0A+=0A+=09if=20(port->peer_cn)=0A+=09{=0A+=09=09= SSL_InvalidateSession(port->pr_fd);=0A+=09=09pfree(port->peer_cn);=0A+=09= =09port->peer_cn=20=3D=20NULL;=0A+=09}=0A+=0A+=09PR_Close(port->pr_fd);=0A= +=09port->pr_fd=20=3D=20NULL;=0A+=09port->ssl_in_use=20=3D=20false;=0A+=0A= +=09if=20(nss_context)=0A+=09{=0A+=09=09= NSS_ShutdownContext(nss_context);=0A+=09=09nss_context=20=3D=20NULL;=0A+=09= }=0A+}=0A+=0A+void=0A+be_tls_destroy(void)=0A+{=0A+=09/*=0A+=09=20*=20It=20= reads=20a=20bit=20odd=20to=20clear=20a=20session=20cache=20when=20we=20= are=20destroying=20the=0A+=09=20*=20context=20altogether,=20but=20if=20= the=20session=20cache=20isn't=20cleared=20before=0A+=09=20*=20shutting=20= down=20the=20context=20it=20will=20fail=20with=20SEC_ERROR_BUSY.=0A+=09=20= */=0A+=09SSL_ClearSessionCache();=0A+}=0A+=0A+int=0A= +be_tls_get_cipher_bits(Port=20*port)=0A+{=0A+=09SECStatus=09=09=09= status;=0A+=09SSLChannelInfo=09=09channel;=0A+=09SSLCipherSuiteInfo=09= suite;=0A+=0A+=09status=20=3D=20SSL_GetChannelInfo(port->pr_fd,=20= &channel,=20sizeof(channel));=0A+=09if=20(status=20!=3D=20SECSuccess)=0A= +=09=09goto=20error;=0A+=0A+=09status=20=3D=20= SSL_GetCipherSuiteInfo(channel.cipherSuite,=20&suite,=20sizeof(suite));=0A= +=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09goto=20error;=0A+=0A+=09= return=20suite.effectiveKeyBits;=0A+=0A+error:=0A+=09ereport(WARNING,=0A= +=09=09=09(errmsg("unable=20to=20extract=20TLS=20session=20information:=20= %s",=0A+=09=09=09=09=09pg_SSLerrmessage(PR_GetError()))));=0A+=09return=20= 0;=0A+}=0A+=0A+/*=0A+=20*=20be_tls_get_compression=0A+=20*=0A+=20*=20NSS=20= disabled=20support=20for=20TLS=20compression=20in=20version=203.33=20and=20= removed=20the=0A+=20*=20code=20in=20a=20subsequent=20release.=20The=20= API=20for=20retrieving=20information=20about=0A+=20*=20compression=20as=20= well=20as=20enabling=20it=20is=20kept=20for=20backwards=20compatibility,=20= but=0A+=20*=20we=20don't=20need=20to=20consult=20it=20since=20it=20was=20= only=20available=20for=20SSLv3=20which=20we=0A+=20*=20don't=20support.=0A= +=20*=0A+=20*=20https://bugzilla.mozilla.org/show_bug.cgi?id=3D1409587=0A= +=20*/=0A+bool=0A+be_tls_get_compression(Port=20*port)=0A+{=0A+=09return=20= false;=0A+}=0A+=0A+const=20char=20*=0A+be_tls_get_version(Port=20*port)=0A= +{=0A+=09SECStatus=09=09=09status;=0A+=09SSLChannelInfo=09=09channel;=0A= +=0A+=09status=20=3D=20SSL_GetChannelInfo(port->pr_fd,=20&channel,=20= sizeof(channel));=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09{=0A+=09=09= ereport(WARNING,=0A+=09=09=09=09(errmsg("unable=20to=20extract=20TLS=20= session=20information:=20%s",=0A+=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()))));=0A+=09=09return=20NULL;=0A+=09}=0A+=0A= +=09return=20ssl_protocol_version_to_string(channel.protocolVersion);=0A= +}=0A+=0A+const=20char=20*=0A+be_tls_get_cipher(Port=20*port)=0A+{=0A+=09= SECStatus=09=09=09status;=0A+=09SSLChannelInfo=09=09channel;=0A+=09= SSLCipherSuiteInfo=09suite;=0A+=0A+=09status=20=3D=20= SSL_GetChannelInfo(port->pr_fd,=20&channel,=20sizeof(channel));=0A+=09if=20= (status=20!=3D=20SECSuccess)=0A+=09=09goto=20error;=0A+=0A+=09status=20=3D= =20SSL_GetCipherSuiteInfo(channel.cipherSuite,=20&suite,=20= sizeof(suite));=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09goto=20= error;=0A+=0A+=09return=20suite.cipherSuiteName;=0A+=0A+error:=0A+=09= ereport(WARNING,=0A+=09=09=09(errmsg("unable=20to=20extract=20TLS=20= session=20information:=20%s",=0A+=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()))));=0A+=09return=20NULL;=0A+}=0A+=0A= +void=0A+be_tls_get_peer_subject_name(Port=20*port,=20char=20*ptr,=20= size_t=20len)=0A+{=0A+=09CERTCertificate=09=20=20=20*certificate;=0A+=0A= +=09certificate=20=3D=20SSL_PeerCertificate(port->pr_fd);=0A+=09if=20= (certificate)=0A+=09=09strlcpy(ptr,=20= CERT_NameToAscii(&certificate->subject),=20len);=0A+=09else=0A+=09=09= ptr[0]=20=3D=20'\0';=0A+}=0A+=0A+void=0A= +be_tls_get_peer_issuer_name(Port=20*port,=20char=20*ptr,=20size_t=20= len)=0A+{=0A+=09CERTCertificate=09=20=20=20=20*certificate;=0A+=0A+=09= certificate=20=3D=20SSL_PeerCertificate(port->pr_fd);=0A+=09if=20= (certificate)=0A+=09=09strlcpy(ptr,=20= CERT_NameToAscii(&certificate->issuer),=20len);=0A+=09else=0A+=09=09= ptr[0]=20=3D=20'\0';=0A+}=0A+=0A+void=0A+be_tls_get_peer_serial(Port=20= *port,=20char=20*ptr,=20size_t=20len)=0A+{=0A+=09CERTCertificate=09=20=20= =20*certificate;=0A+=0A+=09certificate=20=3D=20= SSL_PeerCertificate(port->pr_fd);=0A+=09if=20(certificate)=0A+=09=09= snprintf(ptr,=20len,=20"%li",=20= DER_GetInteger(&(certificate->serialNumber)));=0A+=09else=0A+=09=09= ptr[0]=20=3D=20'\0';=0A+}=0A+=0A+static=20SECStatus=0A= +pg_bad_cert_handler(void=20*arg,=20PRFileDesc=20*fd)=0A+{=0A+=09Port=09=09= =09=20=20=20*port=20=3D=20(Port=20*)=20arg;=0A+=0A+=09= port->peer_cert_valid=20=3D=20false;=0A+=09return=20SECFailure;=0A+}=0A+=0A= +static=20SECStatus=0A+pg_cert_auth_handler(void=20*arg,=20PRFileDesc=20= *fd,=20PRBool=20checksig,=20PRBool=20isServer)=0A+{=0A+=09SECStatus=09=09= =09status;=0A+=09Port=09=09=09=20=20=20*port=20=3D=20(Port=20*)=20arg;=0A= +=09CERTCertificate=09=20=20=20*cert;=0A+=09char=09=09=09=20=20=20= *peer_cn;=0A+=09int=09=09=09=09=09len;=0A+=0A+=09status=20=3D=20= SSL_AuthCertificate(CERT_GetDefaultCertDB(),=20port->pr_fd,=20checksig,=20= PR_TRUE);=0A+=09if=20(status=20=3D=3D=20SECSuccess)=0A+=09{=0A+=09=09= cert=20=3D=20SSL_PeerCertificate(port->pr_fd);=0A+=09=09len=20=3D=20= strlen(cert->subjectName);=0A+=09=09peer_cn=20=3D=20= MemoryContextAllocZero(TopMemoryContext,=20len=20+=201);=0A+=09=09if=20= (strncmp(cert->subjectName,=20"CN=3D",=203)=20=3D=3D=200)=0A+=09=09=09= strlcpy(peer_cn,=20cert->subjectName=20+=20strlen("CN=3D"),=20len=20+=20= 1);=0A+=09=09else=0A+=09=09=09strlcpy(peer_cn,=20cert->subjectName,=20= len=20+=201);=0A+=09=09CERT_DestroyCertificate(cert);=0A+=0A+=09=09= port->peer_cn=20=3D=20peer_cn;=0A+=09=09port->peer_cert_valid=20=3D=20= true;=0A+=09}=0A+=0A+=09return=20status;=0A+}=0A+=0A+/*=20= ------------------------------------------------------------=20*/=0A+/*=09= =09=09=09=09=09Internal=20functions=09=09=09=09=09=09*/=0A+/*=20= ------------------------------------------------------------=20*/=0A+=0A= +static=20PRInt32=0A+pg_ssl_read(PRFileDesc=20*fd,=20void=20*buf,=20= PRInt32=20amount,=20PRIntn=20flags,=0A+=09=09=09PRIntervalTime=20= timeout)=0A+{=0A+=09PRRecvFN=09=09read_fn;=0A+=09PRInt32=09=09=09n_read;=0A= +=0A+=09read_fn=20=3D=20fd->lower->methods->recv;=0A+=09n_read=20=3D=20= read_fn(fd->lower,=20buf,=20amount,=20flags,=20timeout);=0A+=0A+=09= return=20n_read;=0A+}=0A+=0A+static=20PRInt32=0A+pg_ssl_write(PRFileDesc=20= *fd,=20const=20void=20*buf,=20PRInt32=20amount,=20PRIntn=20flags,=0A+=09=09= =09=20PRIntervalTime=20timeout)=0A+{=0A+=09PRSendFN=09=09send_fn;=0A+=09= PRInt32=09=09=09n_write;=0A+=0A+=09send_fn=20=3D=20= fd->lower->methods->send;=0A+=09n_write=20=3D=20send_fn(fd->lower,=20= buf,=20amount,=20flags,=20timeout);=0A+=0A+=09return=20n_write;=0A+}=0A+=0A= +static=20PRFileDesc=20*=0A+init_iolayer(Port=20*port,=20int=20loglevel)=0A= +{=0A+=09const=20PRIOMethods=09=20=20=20*default_methods;=0A+=09= PRFileDesc=09=09=09=20=20=20*layer;=0A+=0A+=09/*=0A+=09=20*=20Start=20by=20= initializing=20our=20layer=20with=20all=20the=20default=20methods=20so=20= that=0A+=09=20*=20we=20can=20selectively=20override=20the=20ones=20we=20= want=20while=20still=20ensuring=20that=0A+=09=20*=20we=20have=20a=20= complete=20layer=20specification.=0A+=09=20*/=0A+=09default_methods=20=3D=20= PR_GetDefaultIOMethods();=0A+=09memcpy(&pr_iomethods,=20default_methods,=20= sizeof(PRIOMethods));=0A+=0A+=09pr_iomethods.recv=20=3D=20pg_ssl_read;=0A= +=09pr_iomethods.send=20=3D=20pg_ssl_write;=0A+=0A+=09/*=0A+=09=20*=20= Each=20IO=20layer=20must=20be=20identified=20by=20a=20unique=20name,=20= where=20uniqueness=20is=0A+=09=20*=20per=20connection.=20Each=20= connection=20in=20a=20postgres=20cluster=20can=20generate=20the=0A+=09=20= *=20identity=20from=20the=20same=20string=20as=20they=20will=20create=20= their=20IO=20layers=20on=0A+=09=20*=20different=20sockets.=20Only=20one=20= layer=20per=20socket=20can=20have=20the=20same=20name.=0A+=09=20*/=0A+=09= pr_id=20=3D=20PR_GetUniqueIdentity("PostgreSQL");=0A+=09if=20(pr_id=20=3D=3D= =20PR_INVALID_IO_LAYER)=0A+=09{=0A+=09=09ereport(loglevel,=0A+=09=09=09=09= (errmsg("out=20of=20memory=20when=20setting=20up=20TLS=20connection")));=0A= +=09=09return=20NULL;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Create=20the=20= actual=20IO=20layer=20as=20a=20stub=20such=20that=20it=20can=20be=20= pushed=20onto=0A+=09=20*=20the=20layer=20stack.=20The=20step=20via=20a=20= stub=20is=20required=20as=20we=20define=20custom=0A+=09=20*=20callbacks.=0A= +=09=20*/=0A+=09layer=20=3D=20PR_CreateIOLayerStub(pr_id,=20= &pr_iomethods);=0A+=09if=20(!layer)=0A+=09{=0A+=09=09ereport(loglevel,=0A= +=09=09=09=09(errmsg("unable=20to=20create=20NSS=20I/O=20layer")));=0A+=09= =09return=20NULL;=0A+=09}=0A+=0A+=09return=20layer;=0A+}=0A+=0A+static=20= char=20*=0A+ssl_protocol_version_to_string(int=20v)=0A+{=0A+=09switch(v)=0A= +=09{=0A+=09=09/*=20SSL=20v2=20and=20v3=20are=20not=20supported=20*/=0A+=09= =09case=20SSL_LIBRARY_VERSION_2:=0A+=09=09case=20= SSL_LIBRARY_VERSION_3_0:=0A+=09=09=09Assert(false);=0A+=09=09=09break;=0A= +=0A+=09=09case=20SSL_LIBRARY_VERSION_TLS_1_0:=0A+=09=09=09return=20= pstrdup("TLSv1.0");=0A+=09=09case=20SSL_LIBRARY_VERSION_TLS_1_1:=0A+=09=09= =09return=20pstrdup("TLSv1.1");=0A+=09=09case=20= SSL_LIBRARY_VERSION_TLS_1_2:=0A+=09=09=09return=20pstrdup("TLSv1.2");=0A= +=09=09case=20SSL_LIBRARY_VERSION_TLS_1_3:=0A+=09=09=09return=20= pstrdup("TLSv1.3");=0A+=09}=0A+=0A+=09return=20pstrdup("unknown");=0A+}=0A= +=0A+=0A+/*=0A+=20*=20ssl_protocol_version_to_nss=0A+=20*=09=09=09= Translate=20PostgreSQL=20TLS=20version=20to=20NSS=20version=0A+=20*=0A+=20= *=20Returns=20zero=20in=20case=20the=20requested=20TLS=20version=20is=20= undefined=20(PG_ANY)=20and=0A+=20*=20should=20be=20set=20by=20the=20= caller,=20or=20-1=20on=20failure.=0A+=20*/=0A+static=20uint16=0A= +ssl_protocol_version_to_nss(int=20v,=20const=20char=20*guc_name)=0A+{=0A= +=09switch(v)=0A+=09{=0A+=09=09/*=0A+=09=09=20*=20There=20is=20no=20= SSL_LIBRARY_=20macro=20defined=20in=20NSS=20with=20the=20value=20zero,=0A= +=09=09=20*=20so=20we=20use=20this=20to=20signal=20the=20caller=20that=20= the=20highest=20useful=20version=0A+=09=09=20*=20should=20be=20set=20on=20= the=20connection.=0A+=09=09=20*/=0A+=09=09case=20PG_TLS_ANY:=0A+=09=09=09= return=200;=0A+=09=09/*=0A+=09=09=20*=20No=20guard=20is=20required=20= here=20as=20there=20are=20no=20versions=20of=20NSS=20without=0A+=09=09=20= *=20support=20for=20TLS1.=0A+=09=09=20*/=0A+=09=09case=20= PG_TLS1_VERSION:=0A+=09=09=09return=20SSL_LIBRARY_VERSION_TLS_1_0;=0A+=09= =09case=20PG_TLS1_1_VERSION:=0A+#ifdef=20SSL_LIBRARY_VERSION_TLS_1_1=0A+=09= =09=09return=20SSL_LIBRARY_VERSION_TLS_1_1;=0A+#else=0A+=09=09=09break;=0A= +#endif=0A+=09=09case=20PG_TLS1_2_VERSION:=0A+#ifdef=20= SSL_LIBRARY_VERSION_TLS_1_2=0A+=09=09=09return=20= SSL_LIBRARY_VERSION_TLS_1_2;=0A+#else=0A+=09=09=09break;=0A+#endif=0A+=09= =09case=20PG_TLS1_3_VERSION:=0A+#ifdef=20SSL_LIBRARY_VERSION_TLS_1_3=0A+=09= =09=09return=20SSL_LIBRARY_VERSION_TLS_1_3;=0A+#else=0A+=09=09=09break;=0A= +#endif=0A+=09=09default:=0A+=09=09=09break;=0A+=09}=0A+=0A+=09return=20= -1;=0A+}=0A+=0A+/*=0A+=20*=20pg_SSLerrmessage=0A+=20*=09=09Create=20and=20= return=20a=20human=20readable=20error=20message=20given=0A+=20*=09=09the=20= specified=20error=20code=0A+=20*=0A+=20*=20PR_ErrorToName=20only=20= converts=20the=20enum=20identifier=20of=20the=20error=20to=20string,=0A+=20= *=20but=20that=20can=20be=20quite=20useful=20for=20debugging=20(and=20in=20= case=20PR_ErrorToString=20is=0A+=20*=20unable=20to=20render=20a=20= message=20then=20we=20at=20least=20have=20something).=0A+=20*/=0A+static=20= char=20*=0A+pg_SSLerrmessage(PRErrorCode=20errcode)=0A+{=0A+=09char=09=09= error[128];=0A+=09int=09=09=09ret;=0A+=0A+=09/*=20TODO:=20this=20should=20= perhaps=20use=20a=20StringInfo=20instead..=20*/=0A+=09ret=20=3D=20= pg_snprintf(error,=20sizeof(error),=20"%s=20(%s)",=0A+=09=09=09=09=09=20=20= PR_ErrorToString(errcode,=20PR_LANGUAGE_I_DEFAULT),=0A+=09=09=09=09=09=20= =20PR_ErrorToName(errcode));=0A+=09if=20(ret)=0A+=09=09return=20= pstrdup(error);=0A+=0A+=09return=20pstrdup(_("unknown=20TLS=20error"));=0A= +}=0Adiff=20--git=20a/src/backend/libpq/be-secure.c=20= b/src/backend/libpq/be-secure.c=0Aindex=202ae507a902..f39977b80c=20= 100644=0A---=20a/src/backend/libpq/be-secure.c=0A+++=20= b/src/backend/libpq/be-secure.c=0A@@=20-49,6=20+49,9=20@@=20bool=09=09= ssl_passphrase_command_supports_reload;=0A=20#ifdef=20USE_SSL=0A=20bool=09= =09ssl_loaded_verify_locations=20=3D=20false;=0A=20#endif=0A+#ifdef=20= USE_NSS=0A+char=09=20=20=20*ssl_database;=0A+#endif=0A=20=0A=20/*=20GUC=20= variable=20controlling=20SSL=20cipher=20list=20*/=0A=20char=09=20=20=20= *SSLCipherSuites=20=3D=20NULL;=0Adiff=20--git=20= a/src/backend/utils/misc/guc.c=20b/src/backend/utils/misc/guc.c=0Aindex=20= 75fc6f11d6..6153745f07=20100644=0A---=20a/src/backend/utils/misc/guc.c=0A= +++=20b/src/backend/utils/misc/guc.c=0A@@=20-4233,7=20+4233,11=20@@=20= static=20struct=20config_string=20ConfigureNamesString[]=20=3D=0A=20=09=09= },=0A=20=09=09&ssl_library,=0A=20#ifdef=20USE_SSL=0A+#if=20= defined(USE_OPENSSL)=0A=20=09=09"OpenSSL",=0A+#elif=20defined(USE_NSS)=0A= +=09=09"NSS",=0A+#endif=0A=20#else=0A=20=09=09"",=0A=20#endif=0A@@=20= -4291,6=20+4295,18=20@@=20static=20struct=20config_string=20= ConfigureNamesString[]=20=3D=0A=20=09=09check_canonical_path,=20= assign_pgstat_temp_directory,=20NULL=0A=20=09},=0A=20=0A+#ifdef=20= USE_NSS=0A+=09{=0A+=09=09{"ssl_database",=20PGC_SIGHUP,=20CONN_AUTH_SSL,=0A= +=09=09=09gettext_noop("Location=20of=20the=20NSS=20certificate=20= database."),=0A+=09=09=09NULL=0A+=09=09},=0A+=09=09&ssl_database,=0A+=09=09= "",=0A+=09=09NULL,=20NULL,=20NULL=0A+=09},=0A+#endif=0A+=0A=20=09{=0A=20=09= =09{"synchronous_standby_names",=20PGC_SIGHUP,=20REPLICATION_MASTER,=0A=20= =09=09=09gettext_noop("Number=20of=20synchronous=20standbys=20and=20list=20= of=20names=20of=20potential=20synchronous=20ones."),=0A@@=20-4319,8=20= +4335,10=20@@=20static=20struct=20config_string=20ConfigureNamesString[]=20= =3D=0A=20=09=09=09GUC_SUPERUSER_ONLY=0A=20=09=09},=0A=20=09=09= &SSLCipherSuites,=0A-#ifdef=20USE_OPENSSL=0A+#if=20defined(USE_OPENSSL)=0A= =20=09=09"HIGH:MEDIUM:+3DES:!aNULL",=0A+#elif=20defined=20(USE_NSS)=0A+=09= =09"",=0A=20#else=0A=20=09=09"none",=0A=20#endif=0Adiff=20--git=20= a/src/include/common/pg_nss.h=20b/src/include/common/pg_nss.h=0Anew=20= file=20mode=20100644=0Aindex=200000000000..38249314d5=0A---=20/dev/null=0A= +++=20b/src/include/common/pg_nss.h=0A@@=20-0,0=20+1,141=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20pg_nss.h=0A+=20*=09=20=20Support=20for=20NSS=20as=20= a=20TLS=20backend=0A+=20*=0A+=20*=20These=20definitions=20are=20used=20= by=20both=20frontend=20and=20backend=20code.=0A+=20*=0A+=20*=20Copyright=20= (c)=202020,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=0A+=20*=20= IDENTIFICATION=0A+=20*=20=20=20=20=20=20=20=20= src/include/common/pg_nss.h=0A+=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#ifndef=20PG_NSS_H=0A+#define=20PG_NSS_H=0A+=0A+#ifdef=20= USE_NSS=0A+=0A+#include=20=0A+=0A+PRUint16=20= pg_find_cipher(char=20*name);=0A+=0A+typedef=20struct=0A+{=0A+=09const=20= char=20=20=20=20=20*name;=0A+=09PRUint16=20=20=20=20=20=20=20=20number;=0A= +}=20NSSCiphers;=0A+=0A+#define=20INVALID_CIPHER=090xFFFF=0A+=0A+/*=0A+=20= *=20This=20list=20is=20a=20partial=20copy=20of=20the=20ciphers=20in=20= NSS=20files=20lib/ssl/sslproto.h=0A+=20*=20in=20order=20to=20provide=20a=20= human=20readable=20version=20of=20the=20ciphers.=20It=20would=20be=0A+=20= *=20nice=20to=20not=20have=20to=20have=20this,=20but=20NSS=20doesn't=20= provide=20any=20API=20addressing=0A+=20*=20the=20ciphers=20by=20name.=20= TODO:=20do=20we=20want=20more=20of=20the=20ciphers,=20or=20perhaps=20= less?=0A+=20*/=0A+static=20const=20NSSCiphers=20NSS_CipherList[]=20=3D=20= {=0A+=0A+=09{"TLS_NULL_WITH_NULL_NULL",=20TLS_NULL_WITH_NULL_NULL},=0A+=0A= +=09{"TLS_RSA_WITH_NULL_MD5",=20TLS_RSA_WITH_NULL_MD5},=0A+=09= {"TLS_RSA_WITH_NULL_SHA",=20TLS_RSA_WITH_NULL_SHA},=0A+=09= {"TLS_RSA_WITH_RC4_128_MD5",=20TLS_RSA_WITH_RC4_128_MD5},=0A+=09= {"TLS_RSA_WITH_RC4_128_SHA",=20TLS_RSA_WITH_RC4_128_SHA},=0A+=09= {"TLS_RSA_WITH_IDEA_CBC_SHA",=20TLS_RSA_WITH_IDEA_CBC_SHA},=0A+=09= {"TLS_RSA_WITH_DES_CBC_SHA",=20TLS_RSA_WITH_DES_CBC_SHA},=0A+=09= {"TLS_RSA_WITH_3DES_EDE_CBC_SHA",=20TLS_RSA_WITH_3DES_EDE_CBC_SHA},=0A+=0A= +=09{"TLS_DH_DSS_WITH_DES_CBC_SHA",=20TLS_DH_DSS_WITH_DES_CBC_SHA},=0A+=09= {"TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",=20= TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA},=0A+=09{"TLS_DH_RSA_WITH_DES_CBC_SHA",=20= TLS_DH_RSA_WITH_DES_CBC_SHA},=0A+=09{"TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",=20= TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA},=0A+=0A+=09= {"TLS_DHE_DSS_WITH_DES_CBC_SHA",=20TLS_DHE_DSS_WITH_DES_CBC_SHA},=0A+=09= {"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",=20= TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_DES_CBC_SHA",=20TLS_DHE_RSA_WITH_DES_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",=20= TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},=0A+=0A+=09= {"TLS_DH_anon_WITH_RC4_128_MD5",=20TLS_DH_anon_WITH_RC4_128_MD5},=0A+=09= {"TLS_DH_anon_WITH_DES_CBC_SHA",=20TLS_DH_anon_WITH_DES_CBC_SHA},=0A+=09= {"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",=20= TLS_DH_anon_WITH_3DES_EDE_CBC_SHA},=0A+=0A+=09= {"TLS_RSA_WITH_AES_128_CBC_SHA",=20TLS_RSA_WITH_AES_128_CBC_SHA},=0A+=09= {"TLS_DH_DSS_WITH_AES_128_CBC_SHA",=20TLS_DH_DSS_WITH_AES_128_CBC_SHA},=0A= +=09{"TLS_DH_RSA_WITH_AES_128_CBC_SHA",=20= TLS_DH_RSA_WITH_AES_128_CBC_SHA},=0A+=09= {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",=20= TLS_DHE_DSS_WITH_AES_128_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",=20= TLS_DHE_RSA_WITH_AES_128_CBC_SHA},=0A+=09= {"TLS_DH_anon_WITH_AES_128_CBC_SHA",=20= TLS_DH_anon_WITH_AES_128_CBC_SHA},=0A+=0A+=09= {"TLS_RSA_WITH_AES_256_CBC_SHA",=20TLS_RSA_WITH_AES_256_CBC_SHA},=0A+=09= {"TLS_DH_DSS_WITH_AES_256_CBC_SHA",=20TLS_DH_DSS_WITH_AES_256_CBC_SHA},=0A= +=09{"TLS_DH_RSA_WITH_AES_256_CBC_SHA",=20= TLS_DH_RSA_WITH_AES_256_CBC_SHA},=0A+=09= {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",=20= TLS_DHE_DSS_WITH_AES_256_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",=20= TLS_DHE_RSA_WITH_AES_256_CBC_SHA},=0A+=09= {"TLS_DH_anon_WITH_AES_256_CBC_SHA",=20= TLS_DH_anon_WITH_AES_256_CBC_SHA},=0A+=09{"TLS_RSA_WITH_NULL_SHA256",=20= TLS_RSA_WITH_NULL_SHA256},=0A+=09{"TLS_RSA_WITH_AES_128_CBC_SHA256",=20= TLS_RSA_WITH_AES_128_CBC_SHA256},=0A+=09= {"TLS_RSA_WITH_AES_256_CBC_SHA256",=20TLS_RSA_WITH_AES_256_CBC_SHA256},=0A= +=0A+=09{"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",=20= TLS_DHE_DSS_WITH_AES_128_CBC_SHA256},=0A+=09= {"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_RSA_WITH_CAMELLIA_128_CBC_SHA},=0A+=09= {"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA},=0A+=09= {"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA},=0A+=09= {"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA},=0A+=09= {"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",=20= TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA},=0A+=0A+=09= {"TLS_DHE_DSS_WITH_RC4_128_SHA",=20TLS_DHE_DSS_WITH_RC4_128_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",=20= TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},=0A+=09= {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",=20= TLS_DHE_DSS_WITH_AES_256_CBC_SHA256},=0A+=09= {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",=20= TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},=0A+=0A+=09= {"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_RSA_WITH_CAMELLIA_256_CBC_SHA},=0A+=09= {"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA},=0A+=09= {"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA},=0A+=09= {"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA},=0A+=09= {"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA},=0A+=09= {"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",=20= TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA},=0A+=0A+=09= {"TLS_RSA_WITH_SEED_CBC_SHA",=20TLS_RSA_WITH_SEED_CBC_SHA},=0A+=0A+=09= {"TLS_RSA_WITH_AES_128_GCM_SHA256",=20TLS_RSA_WITH_AES_128_GCM_SHA256},=0A= +=09{"TLS_RSA_WITH_AES_256_GCM_SHA384",=20= TLS_RSA_WITH_AES_256_GCM_SHA384},=0A+=09= {"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",=20= TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},=0A+=09= {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",=20= TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},=0A+=09= {"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",=20= TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},=0A+=09= {"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",=20= TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},=0A+=0A+=09= {"TLS_AES_128_GCM_SHA256",=20TLS_AES_128_GCM_SHA256},=0A+=09= {"TLS_AES_256_GCM_SHA384",=20TLS_AES_256_GCM_SHA384},=0A+=09= {"TLS_CHACHA20_POLY1305_SHA256",=20TLS_CHACHA20_POLY1305_SHA256},=0A+=09= {NULL,=200}=0A+};=0A+=0A+/*=0A+=20*=20pg_find_cipher=0A+=20*=09=09=09= Translate=20an=20NSS=20ciphername=20to=20the=20cipher=20code=0A+=20*=0A+=20= *=20Searches=20the=20configured=20ciphers=20for=20the=20corresponding=20= cipher=20code=20to=20the=0A+=20*=20name.=20Search=20is=20performed=20= case=20insensitive.=0A+=20*/=0A+PRUint16=0A+pg_find_cipher(char=20*name)=0A= +{=0A+=09const=20NSSCiphers=09*cipher_list=20=3D=20NSS_CipherList;=0A+=0A= +=09while=20(cipher_list->name)=0A+=09{=0A+=09=09if=20= (pg_strcasecmp(cipher_list->name,=20name)=20=3D=3D=200)=0A+=09=09=09= return=20cipher_list->number;=0A+=0A+=09=09cipher_list++;=0A+=09}=0A+=0A= +=09return=200xFFFF;=0A+}=0A+=0A+#endif=09=09=09=09=09=09=09/*=20USE_NSS=20= */=0A+=0A+#endif=09=09=09=09=09=09=09/*=20PG_NSS_H=20*/=0Adiff=20--git=20= a/src/include/libpq/libpq-be.h=20b/src/include/libpq/libpq-be.h=0Aindex=20= 179ebaa104..fc2f16d847=20100644=0A---=20a/src/include/libpq/libpq-be.h=0A= +++=20b/src/include/libpq/libpq-be.h=0A@@=20-192,13=20+192,18=20@@=20= typedef=20struct=20Port=0A=20=09bool=09=09peer_cert_valid;=0A=20=0A=20=09= /*=0A-=09=20*=20OpenSSL=20structures.=20(Keep=20these=20last=20so=20that=20= the=20locations=20of=20other=0A-=09=20*=20fields=20are=20the=20same=20= whether=20or=20not=20you=20build=20with=20OpenSSL.)=0A+=09=20*=20SSL=20= backend=20specific=20structures.=20(Keep=20these=20last=20so=20that=20= the=20locations=0A+=09=20*=20of=20other=20fields=20are=20the=20same=20= whether=20or=20not=20you=20build=20with=20SSL=20enabled.)=0A=20=09=20*/=0A= =20#ifdef=20USE_OPENSSL=0A=20=09SSL=09=09=20=20=20*ssl;=0A=20=09X509=09=20= =20=20*peer;=0A=20#endif=0A+=0A+#ifdef=20USE_NSS=0A+=09//void=09=20=20=20= *ssl;=0A+=09void=09=20=20=20*pr_fd;=0A+#endif=0A=20}=20Port;=0A=20=0A=20= #ifdef=20USE_SSL=0Adiff=20--git=20a/src/include/libpq/libpq.h=20= b/src/include/libpq/libpq.h=0Aindex=20b1152475ac..298d87ecae=20100644=0A= ---=20a/src/include/libpq/libpq.h=0A+++=20b/src/include/libpq/libpq.h=0A= @@=20-88,6=20+88,9=20@@=20extern=20PGDLLIMPORT=20bool=20= ssl_passphrase_command_supports_reload;=0A=20#ifdef=20USE_SSL=0A=20= extern=20bool=20ssl_loaded_verify_locations;=0A=20#endif=0A+#ifdef=20= USE_NSS=0A+extern=20char=20*ssl_database;=0A+#endif=0A=20=0A=20extern=20= int=09secure_initialize(bool=20isServerStart);=0A=20extern=20bool=20= secure_loaded_verify_locations(void);=0Adiff=20--git=20= a/src/include/pg_config.h.in=20b/src/include/pg_config.h.in=0Aindex=20= c199cd46d2..dba1443758=20100644=0A---=20a/src/include/pg_config.h.in=0A= +++=20b/src/include/pg_config.h.in=0A@@=20-889,6=20+889,9=20@@=0A=20/*=20= Define=20to=201=20to=20build=20with=20PAM=20support.=20(--with-pam)=20*/=0A= =20#undef=20USE_PAM=0A=20=0A+/*=20Define=20to=20build=20with=20NSS=20= support=20(--with-nss)=20*/=0A+#undef=20USE_NSS=0A+=0A=20/*=20Define=20= to=201=20to=20use=20software=20CRC-32C=20implementation=20= (slicing-by-8).=20*/=0A=20#undef=20USE_SLICING_BY_8_CRC32C=0A=20=0Adiff=20= --git=20a/src/include/pg_config_manual.h=20= b/src/include/pg_config_manual.h=0Aindex=208f3ec6bde1..2a5b59b998=20= 100644=0A---=20a/src/include/pg_config_manual.h=0A+++=20= b/src/include/pg_config_manual.h=0A@@=20-176,10=20+176,9=20@@=0A=20=0A=20= /*=0A=20=20*=20USE_SSL=20code=20should=20be=20compiled=20only=20when=20= compiling=20with=20an=20SSL=0A-=20*=20implementation.=20=20(Currently,=20= only=20OpenSSL=20is=20supported,=20but=20we=20might=20add=0A-=20*=20more=20= implementations=20in=20the=20future.)=0A+=20*=20implementation.=0A=20=20= */=0A-#ifdef=20USE_OPENSSL=0A+#if=20defined(USE_OPENSSL)=20||=20= defined(USE_NSS)=0A=20#define=20USE_SSL=0A=20#endif=0A=20=0Adiff=20--git=20= a/src/interfaces/libpq/Makefile=20b/src/interfaces/libpq/Makefile=0A= index=20d4919970f8..97821fb39b=20100644=0A---=20= a/src/interfaces/libpq/Makefile=0A+++=20b/src/interfaces/libpq/Makefile=0A= @@=20-57,6=20+57,10=20@@=20OBJS=20+=3D=20\=0A=20=09fe-secure-gssapi.o=0A=20= endif=0A=20=0A+ifeq=20($(with_nss),=20yes)=0A+OBJS=20+=3D=20= fe-secure-nss.o=0A+endif=0A+=0A=20ifeq=20($(PORTNAME),=20cygwin)=0A=20= override=20shlib=20=3D=20cyg$(NAME)$(DLSUFFIX)=0A=20endif=0Adiff=20--git=20= a/src/interfaces/libpq/fe-connect.c=20= b/src/interfaces/libpq/fe-connect.c=0Aindex=2027c9bb46ee..8dd1eb9e5c=20= 100644=0A---=20a/src/interfaces/libpq/fe-connect.c=0A+++=20= b/src/interfaces/libpq/fe-connect.c=0A@@=20-354,6=20+354,12=20@@=20= static=20const=20internalPQconninfoOption=20PQconninfoOptions[]=20=3D=20= {=0A=20=09=09"Target-Session-Attrs",=20"",=2011,=20/*=20= sizeof("read-write")=20=3D=2011=20*/=0A=20=09offsetof(struct=20pg_conn,=20= target_session_attrs)},=0A=20=0A+#if=20defined(USE_NSS)=0A+=09= {"cert_database",=20NULL,=20NULL,=20NULL,=0A+=09=09= "CertificateDatabase",=20"",=2064,=0A+=09offsetof(struct=20pg_conn,=20= cert_database)},=0A+#endif=0A+=0A=20=09/*=20Terminating=20entry=20---=20= MUST=20BE=20LAST=20*/=0A=20=09{NULL,=20NULL,=20NULL,=20NULL,=0A=20=09= NULL,=20NULL,=200}=0Adiff=20--git=20= a/src/interfaces/libpq/fe-secure-nss.c=20= b/src/interfaces/libpq/fe-secure-nss.c=0Anew=20file=20mode=20100644=0A= index=200000000000..863c58f20b=0A---=20/dev/null=0A+++=20= b/src/interfaces/libpq/fe-secure-nss.c=0A@@=20-0,0=20+1,959=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20fe-secure-nss.c=0A+=20*=09=20=20functions=20for=20= supporting=20NSS=20as=20a=20TLS=20backend=20for=20frontend=20libpq=0A+=20= *=0A+=20*=20Portions=20Copyright=20(c)=201996-2020,=20PostgreSQL=20= Global=20Development=20Group=0A+=20*=20Portions=20Copyright=20(c)=20= 1994,=20Regents=20of=20the=20University=20of=20California=0A+=20*=0A+=20= *=20IDENTIFICATION=0A+=20*=09=20=20src/interfaces/libpq/fe-secure-nss.c=0A= +=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+=0A+#include=20"postgres_fe.h"=0A+=0A+#include=20= "libpq-fe.h"=0A+#include=20"fe-auth.h"=0A+#include=20"libpq-int.h"=0A+=0A= +/*=0A+=20*=20BITS_PER_BYTE=20is=20also=20defined=20in=20the=20NSPR=20= header=20fils,=20so=20we=20need=20to=20undef=0A+=20*=20our=20version=20= to=20avoid=20compiler=20warnings=20on=20redefinition.=0A+=20*/=0A= +#define=20pg_BITS_PER_BYTE=20BITS_PER_BYTE=0A+#undef=20BITS_PER_BYTE=0A= +=0A+/*=0A+=20*=20The=20nspr/obsolete/protypes.h=20NSPR=20header=20= typedefs=20uint64=20and=20int64=20with=0A+=20*=20colliding=20definitions=20= from=20ours,=20causing=20a=20much=20expected=20compiler=20error.=0A+=20*=20= The=20definitions=20are=20however=20not=20actually=20used=20in=20NSPR=20= at=20all,=20and=20are=20only=0A+=20*=20intended=20for=20what=20seems=20= to=20be=20backwards=20compatibility=20for=20apps=20written=0A+=20*=20= against=20old=20versions=20of=20NSPR.=20=20The=20following=20comment=20= is=20in=20the=20referenced=0A+=20*=20file,=20and=20was=20added=20in=20= 1998:=0A+=20*=0A+=20*=09=09This=20section=20typedefs=20the=20old=20= 'native'=20types=20to=20the=20new=20PRs.=0A+=20*=09=09These=20= definitions=20are=20scheduled=20to=20be=20eliminated=20at=20the=20= earliest=0A+=20*=09=09possible=20time.=20The=20NSPR=20API=20is=20= implemented=20and=20documented=20using=0A+=20*=09=09the=20new=20= definitions.=0A+=20*=0A+=20*=20As=20there=20is=20no=20opt-out=20from=20= pulling=20in=20these=20typedefs,=20we=20define=20the=20guard=0A+=20*=20= for=20the=20file=20to=20exclude=20it.=20This=20is=20incredibly=20ugly,=20= but=20seems=20to=20be=20about=0A+=20*=20the=20only=20way=20around=20it.=0A= +=20*/=0A+#define=20PROTYPES_H=0A+#include=20=0A+#undef=20= PROTYPES_H=0A+#include=20=0A+#include=20=0A+#include=20= =0A+#include=20=0A+#include=20=0A= +#include=20=0A+#include=20=0A+#include=20=0A= +#include=20=0A+=0A+/*=0A+=20*=20Ensure=20that=20the=20= colliding=20definitions=20match,=20else=20throw=20an=20error.=20In=20= case=0A+=20*=20NSPR=20remove=20the=20definition=20in=20a=20future=20= version=20(however=20unlikely=20that=20may=0A+=20*=20be,=20make=20sure=20= to=20put=20ours=20back=20again.=0A+=20*/=0A+#if=20defined(BITS_PER_BYTE)=0A= +#=20=20if=20BITS_PER_BYTE=20!=3D=20pg_BITS_PER_BYTE=0A+#=20=20=20=20= error=20"incompatible=20byte=20widths=20between=20NSPR=20and=20= PostgreSQL"=0A+#=20=20endif=0A+#else=0A+#=20=20define=20BITS_PER_BYTE=20= pg_BITS_PER_BYTE=0A+#endif=0A+#undef=20pg_BITS_PER_BYTE=0A+=0A+static=20= SECStatus=20pg_load_nss_module(SECMODModule=20**module,=20const=20char=20= *library,=20const=20char=20*name);=0A+static=20SECStatus=20= pg_bad_cert_handler(void=20*arg,=20PRFileDesc=20*fd);=0A+static=20char=20= *pg_SSLerrmessage(PRErrorCode=20errcode);=0A+static=20SECStatus=20= pg_client_auth_handler(void=20*arg,=20PRFileDesc=20*socket,=20= CERTDistNames=20*caNames,=0A+=09=09=09=09=09CERTCertificate=20= **pRetCert,=20SECKEYPrivateKey=20**pRetKey);=0A+static=20SECStatus=20= pg_cert_auth_handler(void=20*arg,=20PRFileDesc=20*fd,=20PRBool=20= checksig,=20PRBool=20isServer);=0A+static=20int=20= ssl_protocol_version_to_nss(const=20char=20*protocol);=0A+static=20bool=20= cert_database_has_CA(PGconn=20*conn);=0A+=0A+static=20char=20= *PQssl_passwd_cb(PK11SlotInfo=20*slot,=20PRBool=20retry,=20void=20*arg);=0A= +=0A+/*=0A+=20*=20PR_ImportTCPSocket()=20is=20a=20private=20API,=20but=20= very=20widely=20used,=20as=20it's=20the=0A+=20*=20only=20way=20to=20make=20= NSS=20use=20an=20already=20set=20up=20POSIX=20file=20descriptor=20rather=0A= +=20*=20than=20opening=20one=20itself.=20To=20quote=20the=20NSS=20= documentation:=0A+=20*=0A+=20*=09=09"In=20theory,=20code=20that=20uses=20= PR_ImportTCPSocket=20may=20break=20when=20NSPR's=0A+=20*=09=09= implementation=20changes.=20In=20practice,=20this=20is=20unlikely=20to=20= happen=20because=0A+=20*=09=09NSPR's=20implementation=20has=20been=20= stable=20for=20years=20and=20because=20of=20NSPR's=0A+=20*=09=09strong=20= commitment=20to=20backward=20compatibility."=0A+=20*=0A+=20*=20= https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/P= R_ImportTCPSocket=0A+=20*=0A+=20*=20The=20function=20is=20declared=20in=20= ,=20but=20as=20it=20is=20a=20header=20marked=0A+=20*=20= private=20we=20declare=20it=20here=20rather=20than=20including=20it.=0A+=20= */=0A+NSPR_API(PRFileDesc*)=20PR_ImportTCPSocket(int);=0A+=0A+static=20= SECMODModule=20*ca_trust=20=3D=20NULL;=0A+static=20NSSInitContext=20= *nss_context=20=3D=20NULL;=0A+=0A+/*=0A+=20*=20Track=20whether=20the=20= NSS=20database=20has=20a=20password=20set=20or=20not.=20There=20is=20no=20= API=0A+=20*=20function=20for=20retrieving=20password=20status,=20so=20we=20= simply=20flip=20this=20to=20true=20in=0A+=20*=20case=20NSS=20invoked=20= the=20password=20callback=20-=20as=20that=20will=20only=20happen=20in=20= case=0A+=20*=20there=20is=20a=20password.=20The=20reason=20for=20= tracking=20this=20is=20that=20there=20are=20calls=0A+=20*=20which=20= require=20a=20password=20parameter,=20but=20doesn't=20use=20the=20= callbacks=20provided,=0A+=20*=20so=20we=20must=20call=20the=20callback=20= on=20behalf=20of=20these.=0A+=20*/=0A+static=20bool=20has_password=20=3D=20= false;=0A+=0A+#if=20defined(WIN32)=0A+static=20const=20char=20= *ca_trust_name=20=3D=20"nssckbi.dll";=0A+#elif=20defined(__darwin__)=0A= +static=20const=20char=20*ca_trust_name=20=3D=20"libnssckbi.dylib";=0A= +#else=0A+static=20const=20char=20*ca_trust_name=20=3D=20= "libnssckbi.so";=0A+#endif=0A+=0A+static=20PQsslKeyPassHook_type_nss=20= PQsslKeyPassHook=20=3D=20NULL;=0A+=0A+/*=20= ------------------------------------------------------------=20*/=0A+/*=09= =09=09=20Procedures=20common=20to=20all=20secure=20sessions=09=09=09*/=0A= +/*=20------------------------------------------------------------=20*/=0A= +=0A+void=0A+pgtls_init_library(bool=20do_ssl,=20int=20do_crypto)=0A+{=0A= +=09/*=20TODO:=20implement=20me=20..=20*/=0A+}=0A+=0A+int=0A= +pgtls_init(PGconn=20*conn)=0A+{=0A+=09conn->ssl_in_use=20=3D=20false;=0A= +=0A+=09return=200;=0A+}=0A+=0A+void=0A+pgtls_close(PGconn=20*conn)=0A+{=0A= +=09if=20(nss_context)=0A+=09{=0A+=09=09= NSS_ShutdownContext(nss_context);=0A+=09=09nss_context=20=3D=20NULL;=0A+=09= }=0A+}=0A+=0A+PostgresPollingStatusType=0A+pgtls_open_client(PGconn=20= *conn)=0A+{=0A+=09SECStatus=09=09=09=09status;=0A+=09PRFileDesc=09=09=09=20= =20=20*pr_fd;=0A+=09PRFileDesc=09=09=09=20=20=20*model;=0A+=09= NSSInitParameters=09=09params;=0A+=09SSLVersionRange=09=09=09= desired_range;=0A+=0A+=09/*=0A+=09=20*=20The=20NSPR=20documentation=20= states=20that=20runtime=20initialization=20via=20PR_Init=20is=0A+=09=20*=20= no=20longer=20required,=20as=20the=20first=20caller=20into=20NSPR=20will=20= perform=20the=0A+=09=20*=20initialization=20implicitly.=20The=20= documentation=20doesn't=20however=20clarify=0A+=09=20*=20from=20which=20= version=20this=20is=20holds=20true,=20so=20let's=20perform=20the=20= potentially=0A+=09=20*=20superfluous=20initialization=20anyways=20to=20= avoid=20crashing=20on=20older=20versions=0A+=09=20*=20of=20NSPR,=20as=20= there=20is=20no=20difference=20in=20overhead.=20=20The=20NSS=20= documentation=0A+=09=20*=20still=20states=20that=20PR_Init=20must=20be=20= called=20in=20some=20way=20(implicitly=20or=0A+=09=20*=20explicitly).=0A= +=09=20*=0A+=09=20*=20The=20below=20parameters=20are=20what=20the=20= implicit=20initialization=20would've=20done=0A+=09=20*=20for=20us,=20and=20= should=20work=20even=20for=20older=20versions=20where=20it=20might=20not=20= be=0A+=09=20*=20done=20automatically.=20The=20last=20parameter,=20= maxPTDs,=20is=20set=20to=20various=0A+=09=20*=20values=20in=20other=20= codebases,=20but=20has=20been=20unused=20since=20NSPR=202.1=20which=20= was=0A+=09=20*=20released=20sometime=20in=201998.=0A+=09=20*/=0A+=09= PR_Init(PR_USER_THREAD,=20PR_PRIORITY_NORMAL,=200);=0A+=0A+=09/*=0A+=09=20= *=20The=20original=20design=20of=20NSS=20was=20for=20a=20single=20= application=20to=20use=20a=20single=0A+=09=20*=20copy=20of=20it,=20= initialized=20with=20NSS_Initialize()=20which=20isn't=20returning=20any=0A= +=09=20*=20handle=20with=20which=20to=20refer=20to=20NSS.=20NSS=20= initialization=20and=20shutdown=20are=0A+=09=20*=20global=20for=20the=20= application,=20so=20a=20shutdown=20in=20another=20NSS=20enabled=20= library=0A+=09=20*=20would=20cause=20NSS=20to=20be=20stopped=20for=20= libpq=20as=20well.=20=20The=20fix=20has=20been=20to=0A+=09=20*=20= introduce=20NSS_InitContext=20which=20returns=20a=20context=20handle=20= to=20pass=20to=0A+=09=20*=20NSS_ShutdownContext.=20=20NSS_InitContext=20= was=20introduced=20in=20NSS=203.12,=20but=0A+=09=20*=20the=20use=20of=20= it=20is=20not=20very=20well=20documented.=0A+=09=20*=20= https://bugzilla.redhat.com/show_bug.cgi?id=3D738456=0A+=09=20*=0A+=09=20= *=20The=20InitParameters=20struct=20passed=20can=20be=20used=20to=20= override=20internal=20values=0A+=09=20*=20in=20NSS,=20but=20the=20usage=20= is=20not=20documented=20at=20all.=20When=20using=20NSS_Init=0A+=09=20*=20= initializations,=20the=20values=20are=20instead=20set=20via=20= PK11_Configure=20calls=20so=0A+=09=20*=20the=20PK11_Configure=20= documentation=20can=20be=20used=20to=20glean=20some=20details=20on=0A+=09= =20*=20these.=0A+=09=20*=0A+=09=20*=20= https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/PKCS11/Modul= e_Specs=0A+=09=20*/=0A+=09memset(¶ms,=200,=20sizeof(params));=0A+=09= params.length=20=3D=20sizeof(params);=0A+=0A+=09if=20= (conn->cert_database=20&&=20strlen(conn->cert_database)=20>=200)=0A+=09{=0A= +=09=09char=20*cert_database_path=20=3D=20psprintf("sql:%s",=20= conn->cert_database);=0A+=0A+=09=09nss_context=20=3D=20= NSS_InitContext(cert_database_path,=20"",=20"",=20"",=0A+=09=09=09=09=09=09= =09=09=09=20=20¶ms,=0A+=09=09=09=09=09=09=09=09=09=20=20= NSS_INIT_READONLY=20|=20NSS_INIT_PK11RELOAD);=0A+=09=09= pfree(cert_database_path);=0A+=09}=0A+=09else=0A+=09=09nss_context=20=3D=20= NSS_InitContext("",=20"",=20"",=20"",=20¶ms,=0A+=09=09=09=09=09=09=09= =09=09=20=20NSS_INIT_READONLY=20|=20NSS_INIT_NOCERTDB=20|=0A+=09=09=09=09= =09=09=09=09=09=20=20NSS_INIT_NOMODDB=20|=20NSS_INIT_FORCEOPEN=20|=0A+=09= =09=09=09=09=09=09=09=09=20=20NSS_INIT_NOROOTINIT=20|=20= NSS_INIT_PK11RELOAD);=0A+=0A+=09if=20(!nss_context)=0A+=09{=0A+=09=09= char=09=09*err=20=3D=20pg_SSLerrmessage(PR_GetError());=0A+=0A+=09=09= printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20=20= libpq_gettext("unable=20to=20%s=20certificate=20database:=20%s"),=0A+=09=09= =09=09=09=09=09=09=09=09conn->cert_database=20?=20"open"=20:=20"create",=0A= +=09=09=09=09=09=09=09=09=09=09err);=0A+=09=09free(err);=0A+=09=09return=20= PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Configure=20= cipher=20policy.=0A+=09=20*/=0A+=09status=20=3D=20= NSS_SetDomesticPolicy();=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09{=0A= +=09=09char=09=09*err=20=3D=20pg_SSLerrmessage(PR_GetError());=0A+=0A+=09= =09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20=20= libpq_gettext("unable=20to=20configure=20cipher=20policy:=20%s"),=0A+=09=09= =09=09=09=09=09=09=09=09err);=0A+=09=09free(err);=0A+=09=09return=20= PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20If=20we=20don't=20= have=20a=20certificate=20database,=20the=20system=20trust=20store=20is=20= the=0A+=09=20*=20fallback=20we=20can=20use.=20If=20we=20fail=20to=20= initialize=20that=20as=20well,=20we=20can=20still=0A+=09=20*=20attempt=20= a=20connection=20as=20long=20as=20the=20sslmode=20isn't=20verify*.=0A+=09= =20*/=0A+=09if=20(!conn->cert_database=20&&=20conn->sslmode[0]=20=3D=3D=20= 'v')=0A+=09{=0A+=09=09status=20=3D=20pg_load_nss_module(&ca_trust,=20= ca_trust_name,=20"\"Root=20Certificates\"");=0A+=09=09//status=20=3D=20= pg_load_nss_module(&ca_trust,=20ca_trust_name,=20"trust");=0A+=09=09if=20= (status=20!=3D=20SECSuccess)=0A+=09=09{=0A+=09=09=09char=20*err=20=3D=20= pg_SSLerrmessage(PR_GetError());=0A+=09=09=09= printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=09=20=20= libpq_gettext("WARNING:=20unable=20to=20load=20NSS=20trust=20module=20= \"%s\"=20:=20%s"),=20ca_trust_name,=20err);=0A+=09=09=09return=20= PGRES_POLLING_FAILED;=0A+=09=09}=0A+=09}=0A+=0A+=0A+=09= PK11_SetPasswordFunc(PQssl_passwd_cb);=0A+=0A+=09/*=0A+=09=20*=20Import=20= the=20already=20opened=20socket=20as=20we=20don't=20want=20to=20use=20= NSPR=20functions=0A+=09=20*=20for=20opening=20the=20network=20socket=20= due=20to=20how=20the=20PostgreSQL=20protocol=20works=0A+=09=20*=20with=20= TLS=20connections.=20This=20function=20is=20not=20part=20of=20the=20NSPR=20= public=20API,=0A+=09=20*=20see=20the=20comment=20at=20the=20top=20of=20= the=20file=20for=20the=20rationale=20of=20still=20using=0A+=09=20*=20it.=0A= +=09=20*/=0A+=09pr_fd=20=3D=20PR_ImportTCPSocket(conn->sock);=0A+=09if=20= (!pr_fd)=0A+=09{=0A+=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09= =09=09=09=09=20=20libpq_gettext("unable=20to=20attach=20to=20socket:=20= %s"),=0A+=09=09=09=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A= +=09=09return=20PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= Most=20of=20the=20documentation=20available,=20and=20implementations=20= of,=20NSS/NSPR=0A+=09=20*=20use=20the=20PR_NewTCPSocket()=20function=20= here,=20which=20has=20the=20drawback=20that=20it=0A+=09=20*=20can=20only=20= create=20IPv4=20sockets.=20Instead=20use=20PR_OpenTCPSocket()=20which=20= copes=0A+=09=20*=20with=20IPv6=20as=20well.=0A+=09=20*/=0A+=09model=20=3D=20= SSL_ImportFD(NULL,=20PR_OpenTCPSocket(conn->laddr.addr.ss_family));=0A+=09= if=20(!model)=0A+=09{=0A+=09=09printfPQExpBuffer(&conn->errorMessage,=0A= +=09=09=09=09=09=09=20=20libpq_gettext("unable=20to=20enable=20TLS:=20= %s"),=0A+=09=09=09=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A= +=09=09return=20PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=20Disable=20= old=20protocol=20versions=20(SSLv2=20and=20SSLv3)=20*/=0A+=09= SSL_OptionSet(model,=20SSL_ENABLE_SSL2,=20PR_FALSE);=0A+=09= SSL_OptionSet(model,=20SSL_V2_COMPATIBLE_HELLO,=20PR_FALSE);=0A+=09= SSL_OptionSet(model,=20SSL_ENABLE_SSL3,=20PR_FALSE);=0A+=0A+#ifdef=20= SSL_CBC_RANDOM_IV=0A+=09/*=0A+=09=20*=20Enable=20protection=20against=20= the=20BEAST=20attack=20in=20case=20the=20NSS=20library=20has=0A+=09=20*=20= support=20for=20that.=20While=20SSLv3=20is=20disabled,=20we=20may=20= still=20allow=20TLSv1=0A+=09=20*=20which=20is=20affected.=20The=20option=20= isn't=20documented=20as=20an=20SSL=20option,=20but=20as=0A+=09=20*=20an=20= NSS=20environment=20variable.=0A+=09=20*/=0A+=09SSL_OptionSet(model,=20= SSL_CBC_RANDOM_IV,=20PR_TRUE);=0A+#endif=0A+=0A+=09/*=20Set=20us=20up=20= as=20a=20TLS=20client=20for=20the=20handshake=20*/=0A+=09= SSL_OptionSet(model,=20SSL_HANDSHAKE_AS_CLIENT,=20PR_TRUE);=0A+=0A+=09/*=0A= +=09=20*=20When=20setting=20the=20available=20protocols,=20we=20either=20= use=20the=20user=20defined=0A+=09=20*=20configuration=20values,=20and=20= if=20missing=20we=20accept=20whatever=20is=20the=20highest=0A+=09=20*=20= version=20supported=20by=20the=20library=20as=20the=20max=20and=20only=20= limit=20the=20range=20in=0A+=09=20*=20the=20other=20end=20at=20TLSv1.0.=20= ssl_variant_stream=20is=20a=20ProtocolVariant=20enum=0A+=09=20*=20for=20= Stream=20protocols,=20rather=20than=20datagram.=0A+=09=20*/=0A+=09= SSL_VersionRangeGetSupported(ssl_variant_stream,=20&desired_range);=0A+=09= desired_range.min=20=3D=20SSL_LIBRARY_VERSION_TLS_1_0;=0A+=0A+=09if=20= (conn->ssl_min_protocol_version=20&&=20= strlen(conn->ssl_min_protocol_version)=20>=200)=0A+=09{=0A+=09=09int=20= ssl_min_ver=20=3D=20= ssl_protocol_version_to_nss(conn->ssl_min_protocol_version);=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=20value=20\"%s\"=20for=20minimum=20version=20of=20= SSL=20protocol\n"),=0A+=09=09=09=09=09=09=09=20=20= conn->ssl_min_protocol_version);=0A+=09=09=09return=20-1;=0A+=09=09}=0A+=0A= +=09=09desired_range.min=20=3D=20ssl_min_ver;=0A+=09}=0A+=0A+=09if=20= (conn->ssl_max_protocol_version=20&&=20= strlen(conn->ssl_max_protocol_version)=20>=200)=0A+=09{=0A+=09=09int=20= ssl_max_ver=20=3D=20= ssl_protocol_version_to_nss(conn->ssl_max_protocol_version);=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=20value=20\"%s\"=20for=20maximum=20version=20of=20= SSL=20protocol\n"),=0A+=09=09=09=09=09=09=09=20=20= conn->ssl_max_protocol_version);=0A+=09=09=09return=20-1;=0A+=09=09}=0A+=0A= +=09=09desired_range.max=20=3D=20ssl_max_ver;=0A+=09}=0A+=0A+=09if=20= (SSL_VersionRangeSet(model,=20&desired_range)=20!=3D=20SECSuccess)=0A+=09= {=0A+=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20= =20libpq_gettext("unable=20to=20set=20allowed=20SSL=20protocol=20version=20= range:=20%s"),=0A+=09=09=09=09=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()));=0A+=09=09return=20= PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Set=20up=20= callback=20for=20verifying=20server=20certificates,=20as=20well=20as=20= for=20how=0A+=09=20*=20to=20handle=20failed=20verifications.=0A+=09=20*/=0A= +=09SSL_AuthCertificateHook(model,=20pg_cert_auth_handler,=20(void=20*)=20= conn);=0A+=09SSL_BadCertHook(model,=20pg_bad_cert_handler,=20(void=20*)=20= conn);=0A+=0A+=09/*=0A+=09=20*=20Convert=20the=20NSPR=20socket=20to=20an=20= SSL=20socket.=20Ensuring=20the=20success=20of=20this=0A+=09=20*=20= operation=20is=20critical=20as=20NSS=20SSL_*=20functions=20may=20return=20= SECSuccess=20on=0A+=09=20*=20the=20socket=20even=20though=20SSL=20hasn't=20= been=20enabled,=20which=20introduce=20a=20risk=0A+=09=20*=20of=20silent=20= downgrades.=0A+=09=20*/=0A+=09conn->pr_fd=20=3D=20SSL_ImportFD(model,=20= pr_fd);=0A+=09if=20(!conn->pr_fd)=0A+=09{=0A+=09=09= printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20=20= libpq_gettext("unable=20to=20configure=20client=20for=20TLS:=20%s"),=0A+=09= =09=09=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A+=09=09= return=20PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20The=20= model=20can=20now=20we=20closed=20as=20we've=20applied=20the=20settings=20= of=20the=20model=0A+=09=20*=20onto=20the=20real=20socket.=20=46rom=20= hereon=20we=20should=20only=20use=20conn->pr_fd.=0A+=09=20*/=0A+=09= PR_Close(model);=0A+=0A+=09/*=20Set=20the=20private=20data=20to=20be=20= passed=20to=20the=20password=20callback=20*/=0A+=09= SSL_SetPKCS11PinArg(conn->pr_fd,=20(void=20*)=20conn);=0A+=0A+=09/*=0A+=09= =20*=20If=20a=20CRL=20file=20has=20been=20specified,=20verify=20if=20it=20= exists=20in=20the=20database=0A+=09=20*=20but=20don't=20fail=20in=20case=20= it=20doesn't.=0A+=09=20*/=0A+=09if=20(conn->sslcrl=20&&=20= strlen(conn->sslcrl)=20>=200)=0A+=09{=0A+=09=09/*=20XXX:=20Implement=20= me..=20*/=0A+=09}=0A+=0A+=09status=20=3D=20= SSL_ResetHandshake(conn->pr_fd,=20PR_FALSE);=0A+=09if=20(status=20!=3D=20= SECSuccess)=0A+=09{=0A+=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09= =09=09=09=09=09=20=20libpq_gettext("unable=20to=20initiate=20handshake:=20= %s"),=0A+=09=09=09=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A= +=09=09return=20PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= Set=20callback=20for=20client=20authentication=20when=20requested=20by=20= the=20server.=0A+=09=20*/=0A+=09SSL_GetClientAuthDataHook(conn->pr_fd,=20= pg_client_auth_handler,=20(void=20*)=20conn);=0A+=0A+=09/*=0A+=09=20*=20= Specify=20which=20hostname=20we=20are=20expecting=20to=20talk=20to.=20= This=20is=20required,=0A+=09=20*=20albeit=20mostly=20applies=20to=20when=20= opening=20a=20connection=20to=20a=20traditional=0A+=09=20*=20http=20= server=20it=20seems.=0A+=09=20*/=0A+=09SSL_SetURL(conn->pr_fd,=20= (conn->connhost[conn->whichhost]).host);=0A+=0A+=09do=0A+=09{=0A+=09=09= status=20=3D=20SSL_ForceHandshake(conn->pr_fd);=0A+=09}=0A+=09while=20= (status=20!=3D=20SECSuccess=20&&=20PR_GetError()=20=3D=3D=20= PR_WOULD_BLOCK_ERROR);=0A+=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09= {=0A+=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20= =20libpq_gettext("SSL=20error:=20%s"),=0A+=09=09=09=09=09=09=09=09=09=09= pg_SSLerrmessage(PR_GetError()));=0A+=09=09return=20= PGRES_POLLING_FAILED;=0A+=09}=0A+=0A+=09conn->ssl_in_use=20=3D=20true;=0A= +=09return=20PGRES_POLLING_OK;=0A+}=0A+=0A+ssize_t=0A+pgtls_read(PGconn=20= *conn,=20void=20*ptr,=20size_t=20len)=0A+{=0A+=09PRInt32=09=09=09nread;=0A= +=09PRErrorCode=09=09status;=0A+=09int=09=09=09=09read_errno=20=3D=200;=0A= +=0A+=09nread=20=3D=20PR_Recv(conn->pr_fd,=20ptr,=20len,=200,=20= PR_INTERVAL_NO_WAIT);=0A+=0A+=09/*=0A+=09=20*=20PR_Recv=20blocks=20until=20= there=20is=20data=20to=20read=20or=20the=20timeout=20expires.=20Zero=0A+=09= =20*=20is=20returned=20for=20closed=20connections,=20while=20-1=20= indicates=20an=20error=20within=0A+=09=20*=20the=20ongoing=20connection.=0A= +=09=20*/=0A+=09if=20(nread=20=3D=3D=200)=0A+=09{=0A+=09=09read_errno=20= =3D=20ECONNRESET;=0A+=09=09return=20-1;=0A+=09}=0A+=0A+=09if=20(nread=20= =3D=3D=20-1)=0A+=09{=0A+=09=09status=20=3D=20PR_GetError();=0A+=0A+=09=09= switch(status)=0A+=09=09{=0A+=09=09=09case=20PR_WOULD_BLOCK_ERROR:=0A+=09= =09=09=09read_errno=20=3D=20EINTR;=0A+=09=09=09=09break;=0A+=0A+=09=09=09= case=20PR_IO_TIMEOUT_ERROR:=0A+=09=09=09=09break;=0A+=09=09=09/*=0A+=09=09= =09=20*=20The=20error=20cases=20for=20PR_Recv=20are=20not=20documented,=20= but=20can=20be=0A+=09=09=09=20*=20reverse=20engineered=20from=20= _MD_unix_map_default_error()=20in=20the=0A+=09=09=09=20*=20NSPR=20code,=20= defined=20in=20pr/src/md/unix/unix_errors.c.=0A+=09=09=09=20*/=0A+=09=09=09= default:=0A+=09=09=09=09printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09= =09=09=09=09=09=20=20libpq_gettext("TLS=20read=20error:=20%s"),=0A+=09=09= =09=09=09=09=09=09=09=09=09=09pg_SSLerrmessage(status));=0A+=09=09=09=09= break;=0A+=09=09}=0A+=09}=0A+=0A+=09SOCK_ERRNO_SET(read_errno);=0A+=09= return=20(ssize_t)=20nread;=0A+}=0A+=0A+/*=0A+=20*=20pgtls_read_pending=0A= +=20*=09=09Check=20for=20the=20existence=20of=20data=20to=20be=20read.=0A= +=20*=0A+=20*=20This=20is=20part=20of=20the=20PostgreSQL=20TLS=20backend=20= API.=0A+=20*/=0A+bool=0A+pgtls_read_pending(PGconn=20*conn)=0A+{=0A+=09= unsigned=20char=09c;=0A+=09int=09=09=09=09n;=0A+=0A+=09/*=0A+=09=20*=20= PR_Recv=20peeks=20into=20the=20stream=20with=20the=20timeount=20turned=20= off,=20to=20see=20if=0A+=09=20*=20there=20is=20another=20byte=20to=20= read=20off=20the=20wire.=20There=20is=20an=20NSS=20function=0A+=09=20*=20= SSL_DataPending()=20which=20might=20seem=20like=20a=20better=20fit,=20= but=20it=20will=20only=0A+=09=20*=20check=20already=20encrypted=20data=20= in=20the=20SSL=20buffer,=20not=20still=20unencrypted=0A+=09=20*=20data,=20= thus=20it=20doesn't=20guarantee=20that=20a=20subsequent=20call=20to=0A+=09= =20*=20PR_Read/PR_Recv=20wont=20block.=0A+=09=20*/=0A+=09n=20=3D=20= PR_Recv(conn->pr_fd,=20&c,=201,=20PR_MSG_PEEK,=20PR_INTERVAL_NO_WAIT);=0A= +=09return=20(n=20>=200);=0A+}=0A+=0A+ssize_t=0A+pgtls_write(PGconn=20= *conn,=20const=20void=20*ptr,=20size_t=20len)=0A+{=0A+=09PRInt32=09=09=09= n;=0A+=09PRErrorCode=09=09status;=0A+=09int=09=09=09=09write_errno=20=3D=20= 0;=0A+=0A+=09n=20=3D=20PR_Write(conn->pr_fd,=20ptr,=20len);=0A+=0A+=09if=20= (n=20<=200)=0A+=09{=0A+=09=09status=20=3D=20PR_GetError();=0A+=0A+=09=09= switch(status)=0A+=09=09{=0A+=09=09=09case=20PR_WOULD_BLOCK_ERROR:=0A= +#ifdef=20EAGAIN=0A+=09=09=09=09write_errno=20=3D=20EAGAIN;=0A+#else=0A+=09= =09=09=09write_errno=20=3D=20EINTR;=0A+#endif=0A+=09=09=09=09break;=0A+=0A= +=09=09=09default:=0A+=09=09=09=09printfPQExpBuffer(&conn->errorMessage,=0A= +=09=09=09=09=09=09=09=09=20=20libpq_gettext("TLS=20write=20error:=20= %s"),=0A+=09=09=09=09=09=09=09=09=09=09=09=09pg_SSLerrmessage(status));=0A= +=09=09=09=09write_errno=20=3D=20ECONNRESET;=0A+=09=09=09=09break;=0A+=09= =09}=0A+=09}=0A+=0A+=09SOCK_ERRNO_SET(write_errno);=0A+=09return=20= (ssize_t)=20n;=0A+}=0A+=0A+/*=20= ------------------------------------------------------------=20*/=0A+/*=09= =09=09PostgreSQL=20specific=20TLS=20support=20functions=09=09=09*/=0A+/*=20= ------------------------------------------------------------=20*/=0A+=0A= +/*=0A+=20*=20TODO:=20this=20a=2099%=20copy=20of=20the=20same=20function=20= in=20the=20backend,=20make=20these=20share=0A+=20*=20a=20single=20= implementation=20instead.=0A+=20*/=0A+static=20char=20*=0A= +pg_SSLerrmessage(PRErrorCode=20errcode)=0A+{=0A+=09const=20char=20= *error;=0A+=0A+=09error=20=3D=20PR_ErrorToName(errcode);=0A+=09if=20= (error)=0A+=09=09return=20strdup(error);=0A+=0A+=09return=20= strdup("unknown=20TLS=20error");=0A+}=0A+=0A+static=20SECStatus=0A= +pg_load_nss_module(SECMODModule=20**module,=20const=20char=20*library,=20= const=20char=20*name)=0A+{=0A+=09SECMODModule=20=20=20*mod;=0A+=09char=09= =09=20=20=20*modulespec;=0A+=0A+=09modulespec=20=3D=20= psprintf("library=3D\"%s\",=20name=3D\"%s\"",=20library,=20name);=0A+=0A= +=09/*=0A+=09=20*=20Attempt=20to=20load=20the=20specified=20module.=20= The=20second=20parameter=20is=20"parent"=0A+=09=20*=20which=20should=20= always=20be=20NULL=20for=20application=20code.=20The=20third=20parameter=0A= +=09=20*=20defines=20if=20loading=20should=20recurse=20which=20is=20only=20= applicable=20when=20loading=0A+=09=20*=20a=20module=20from=20within=20= another=20module.=20This=20hierarchy=20would=20have=20to=20be=0A+=09=20*=20= defined=20in=20the=20modulespec,=20and=20since=20we=20don't=20support=20= anything=20but=0A+=09=20*=20directly=20addressed=20modules=20we=20should=20= pass=20PR_FALSE.=0A+=09=20*/=0A+=09mod=20=3D=20= SECMOD_LoadUserModule(modulespec,=20NULL,=20PR_FALSE);=0A+=09= pfree(modulespec);=0A+=0A+=09if=20(mod=20&&=20mod->loaded)=0A+=09{=0A+=09= =09*module=20=3D=20mod;=0A+=09=09return=20SECSuccess;=0A+=09}=0A+=0A+=09= SECMOD_DestroyModule(mod);=0A+=09return=20SECFailure;=0A+}=0A+=0A+/*=20= ------------------------------------------------------------=20*/=0A+/*=09= =09=09=09=09=09NSS=20Callbacks=09=09=09=09=09=09=09*/=0A+/*=20= ------------------------------------------------------------=20*/=0A+=0A= +/*=0A+=20*=20pg_cert_auth_handler=0A+=20*=09=09=09Callback=20for=20= authenticating=20server=20certificate=0A+=20*=0A+=20*=20This=20is=20= pretty=20much=20the=20same=20procedure=20as=20the=20SSL_AuthCertificate=20= function=0A+=20*=20provided=20by=20NSS,=20with=20the=20difference=20= being=20server=20hostname=20validation.=20With=0A+=20*=20= SSL_AuthCertificate=20there=20is=20no=20way=20to=20do=20verify-ca,=20it=20= only=20does=20the=20-full=0A+=20*=20flavor=20of=20our=20sslmodes,=20so=20= we=20need=20our=20own=20implementation.=0A+=20*/=0A+static=20SECStatus=0A= +pg_cert_auth_handler(void=20*arg,=20PRFileDesc=20*fd,=20PRBool=20= checksig,=20PRBool=20isServer)=0A+{=0A+=09SECStatus=09=09=09status;=0A+=09= PGconn=09=09=09=20=20=20*conn=20=3D=20(PGconn=20*)=20arg;=0A+=09char=09=09= =09=20=20=20*server_hostname=20=3D=20NULL;=0A+=09CERTCertificate=09=20=20= =20*server_cert;=0A+=09void=09=09=09=20=20=20*pin;=0A+=0A+=09= Assert(!isServer);=0A+=0A+=09pin=20=3D=20SSL_RevealPinArg(conn->pr_fd);=0A= +=09server_cert=20=3D=20SSL_PeerCertificate(conn->pr_fd);=0A+=0A+=09= status=20=3D=20CERT_VerifyCertificateNow((CERTCertDBHandle=20*)=20= CERT_GetDefaultCertDB(),=20server_cert,=0A+=09=09=09=09=09=09=09=09=09=20= =20=20checksig,=20certificateUsageSSLServer,=0A+=09=09=09=09=09=09=09=09=09= =20=20=20pin,=20NULL);=0A+=0A+=09/*=0A+=09=20*=20If=20we've=20already=20= failed=20validation=20then=20there=20is=20no=20point=20in=20also=0A+=09=20= *=20performing=20the=20hostname=20check=20for=20verify-full.=0A+=09=20*/=0A= +=09if=20(status=20!=3D=20SECSuccess)=0A+=09{=0A+=09=09= printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=20=20= libpq_gettext("unable=20to=20verify=20certificate:=20%s"),=0A+=09=09=09=09= =09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A+=09=09goto=20= done;=0A+=09}=0A+=0A+=09if=20(strcmp(conn->sslmode,=20"verify-full")=20= =3D=3D=200)=0A+=09{=0A+=09=09server_hostname=20=3D=20= SSL_RevealURL(conn->pr_fd);=0A+=09=09if=20(!server_hostname=20||=20= server_hostname[0]=20=3D=3D=20'\0')=0A+=09=09=09goto=20done;=0A+=0A+=09=09= /*=0A+=09=09=20*=20CERT_VerifyCertName=20will=20internally=20perform=20= RFC=202818=20SubjectAltName=0A+=09=09=20*=20verification.=0A+=09=09=20*/=0A= +=09=09status=20=3D=20CERT_VerifyCertName(server_cert,=20= server_hostname);=0A+=09=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09=09= printfPQExpBuffer(&conn->errorMessage,=0A+=09=09=09=09=09=09=09=20=20= libpq_gettext("unable=20to=20verify=20server=20hostname:=20%s"),=0A+=09=09= =09=09=09=09=09=09=09=09=09pg_SSLerrmessage(PR_GetError()));=0A+=0A+=09}=0A= +=0A+done:=0A+=09if=20(server_hostname)=0A+=09=09= PR_Free(server_hostname);=0A+=0A+=09= CERT_DestroyCertificate(server_cert);=0A+=09return=20status;=0A+}=0A+=0A= +/*=0A+=20*=20pg_client_auth_handler=0A+=20*=09=09Callback=20for=20= client=20certificate=20validation=0A+=20*=0A+=20*=20The=20client=20auth=20= callback=20is=20not=20on=20by=20default=20in=20NSS,=20so=20we=20need=20= to=20invoke=0A+=20*=20it=20ourselves=20to=20ensure=20we=20can=20do=20= cert=20authentication.=20A=20TODO=20is=20to=20support=0A+=20*=20running=20= without=20a=20specified=20sslcert=20parameter.=20By=20retrieving=20all=20= the=20certs=0A+=20*=20via=20nickname=20from=20the=20cert=20database=20= and=20see=20if=20we=20find=20one=20which=20apply=20with=0A+=20*=20= NSS_CmpCertChainWCANames()=20and=20PK11_FindKeyByAnyCert()=20we=20could=20= support=0A+=20*=20just=20running=20with=20a=20ssl=20database=20= specified.=0A+=20*=0A+=20*=20For=20now,=20we=20use=20the=20default=20= client=20certificate=20validation=20which=20requires=20a=0A+=20*=20= defined=20nickname=20to=20identify=20the=20cert=20in=20the=20database.=0A= +=20*/=0A+static=20SECStatus=0A+pg_client_auth_handler(void=20*arg,=20= PRFileDesc=20*socket,=20CERTDistNames=20*caNames,=0A+=09=09=09=09=09=20=20= =20CERTCertificate=20**pRetCert,=20SECKEYPrivateKey=20**pRetKey)=0A+{=0A= +=09PGconn=09=09=20=20=20*conn=20=3D=20(PGconn=20*)=20arg;=0A+=0A+=09= return=20NSS_GetClientAuthData(conn->sslcert,=20socket,=20caNames,=20= pRetCert,=20pRetKey);=0A+}=0A+=0A+/*=0A+=20*=20pg_bad_cert_handler=0A+=20= *=09=09Callback=20for=20failed=20certificate=20validation=0A+=20*=0A+=20= *=20The=20TLS=20handshake=20will=20call=20this=20function=20iff=20the=20= server=20certificate=20failed=0A+=20*=20validation.=20Depending=20on=20= the=20sslmode,=20we=20allow=20the=20connection=20anyways.=0A+=20*/=0A= +static=20SECStatus=0A+pg_bad_cert_handler(void=20*arg,=20PRFileDesc=20= *fd)=0A+{=0A+=09PGconn=09=09=20=20=20*conn=20=3D=20(PGconn=20*)=20arg;=0A= +=09PRErrorCode=09=09err;=0A+=0A+=09/*=0A+=09=20*=20This=20really=20= shouldn't=20happen,=20as=20we've=20the=20the=20PGconn=20object=20as=20= our=0A+=09=20*=20callback=20data,=20and=20at=20the=20callsite=20we=20= know=20it=20will=20be=20populated.=20That=0A+=09=20*=20being=20said,=20= the=20NSS=20code=20itself=20performs=20this=20check=20even=20when=20it=20= should=0A+=09=20*=20not=20be=20required=20so=20let's=20use=20the=20same=20= belts=20with=20our=20suspenders.=0A+=09=20*/=0A+=09if=20(!arg)=0A+=09=09= return=20SECFailure;=0A+=0A+=09/*=0A+=09=20*=20For=20sslmodes=20other=20= than=20verify-full=20and=20verify-ca=20we=20don't=20perform=20peer=0A+=09= =20*=20validation,=20so=20return=20immediately.=20=20sslmode=20require=20= with=20a=20database=0A+=09=20*=20specified=20which=20contains=20a=20CA=20= certificate=20will=20work=20like=20verify-ca=20to=20be=0A+=09=20*=20= compatible=20with=20the=20OpenSSL=20implementation.=0A+=09=20*/=0A+=09if=20= (strcmp(conn->sslmode,=20"require")=20=3D=3D=200)=0A+=09{=0A+=09=09if=20= (conn->cert_database=20&&=20strlen(conn->cert_database)=20>=200=20&&=20= cert_database_has_CA(conn))=0A+=09=09=09return=20SECFailure;=0A+=09}=0A+=09= if=20(conn->sslmode[0]=20=3D=3D=20'v')=0A+=09=09return=20SECFailure;=0A+=0A= +=09err=20=3D=20PORT_GetError();=0A+=0A+=09/*=0A+=09=20*=20TODO:=20these=20= are=20relevant=20error=20codes=20that=20can=20occur=20in=20certificate=0A= +=09=20*=20validation,=20figure=20out=20which=20we=20dont=20want=20for=20= require/prefer=20etc.=0A+=09=20*/=0A+=09switch=20(err)=0A+=09{=0A+=09=09= case=20SEC_ERROR_INVALID_AVA:=0A+=09=09case=20SEC_ERROR_INVALID_TIME:=0A= +=09=09case=20SEC_ERROR_BAD_SIGNATURE:=0A+=09=09case=20= SEC_ERROR_EXPIRED_CERTIFICATE:=0A+=09=09case=20SEC_ERROR_UNKNOWN_ISSUER:=0A= +=09=09case=20SEC_ERROR_UNTRUSTED_ISSUER:=0A+=09=09case=20= SEC_ERROR_UNTRUSTED_CERT:=0A+=09=09case=20SEC_ERROR_CERT_VALID:=0A+=09=09= case=20SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:=0A+=09=09case=20= SEC_ERROR_CRL_EXPIRED:=0A+=09=09case=20SEC_ERROR_CRL_BAD_SIGNATURE:=0A+=09= =09case=20SEC_ERROR_EXTENSION_VALUE_INVALID:=0A+=09=09case=20= SEC_ERROR_CA_CERT_INVALID:=0A+=09=09case=20= SEC_ERROR_CERT_USAGES_INVALID:=0A+=09=09case=20= SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:=0A+=09=09=09return=20SECSuccess;=0A= +=09=09=09break;=0A+=09=09default:=0A+=09=09=09return=20SECFailure;=0A+=09= =09=09break;=0A+=09}=0A+=0A+=09/*=20Unreachable=20*/=0A+=09return=20= SECSuccess;=0A+}=0A+=0A+/*=20= ------------------------------------------------------------=20*/=0A+/*=09= =09=09=09=09SSL=20information=20functions=09=09=09=09=09*/=0A+/*=20= ------------------------------------------------------------=20*/=0A+=0A= +void=20*=0A+PQgetssl(PGconn=20*conn)=0A+{=0A+=09/*=0A+=09=20*=20Always=20= return=20NULL=20as=20this=20is=20legacy=20and=20defined=20to=20be=20= equal=20to=0A+=09=20*=20PQsslStruct(conn,=20"OpenSSL");=20This=20should=20= ideally=20trigger=20a=20logged=0A+=09=20*=20warning=20somewhere=20as=20= it's=20nonsensical=20to=20run=20in=20a=20non-OpenSSL=20build,=0A+=09=20*=20= but=20the=20color=20of=20said=20bikeshed=20hasn't=20yet=20been=20= determined.=0A+=09=20*/=0A+=09return=20NULL;=0A+}=0A+=0A+void=20*=0A= +PQsslStruct(PGconn=20*conn,=20const=20char=20*struct_name)=0A+{=0A+=09= if=20(!conn)=0A+=09=09return=20NULL;=0A+=0A+=09/*=0A+=09=20*=20Return=20= the=20underlying=20PRFileDesc=20which=20can=20be=20used=20to=20access=20= information=0A+=09=20*=20on=20the=20connection=20details.=20There=20is=20= no=20SSL=20context=20per=20se.=0A+=09=20*/=0A+=09if=20= (strcmp(struct_name,=20"NSS")=20=3D=3D=200)=0A+=09=09return=20= conn->pr_fd;=0A+=09return=20NULL;=0A+}=0A+=0A+const=20char=20*const=20*=0A= +PQsslAttributeNames(PGconn=20*conn)=0A+{=0A+=09static=20const=20char=20= *const=20result[]=20=3D=20{=0A+=09=09"library",=0A+=09=09"cipher",=0A+=09= =09"protocol",=0A+=09=09"key_bits",=0A+=09=09"compression",=0A+=09=09= NULL=0A+=09};=0A+=0A+=09return=20result;=0A+}=0A+=0A+const=20char=20*=0A= +PQsslAttribute(PGconn=20*conn,=20const=20char=20*attribute_name)=0A+{=0A= +=09SECStatus=09=09=09status;=0A+=09SSLChannelInfo=09=09channel;=0A+=09= SSLCipherSuiteInfo=09suite;=0A+=0A+=09if=20(!conn=20||=20!conn->pr_fd)=0A= +=09=09return=20NULL;=0A+=0A+=09if=20(strcmp(attribute_name,=20= "library")=20=3D=3D=200)=0A+=09=09return=20"NSS";=0A+=0A+=09status=20=3D=20= SSL_GetChannelInfo(conn->pr_fd,=20&channel,=20sizeof(channel));=0A+=09if=20= (status=20!=3D=20SECSuccess)=0A+=09=09return=20NULL;=0A+=0A+=09status=20= =3D=20SSL_GetCipherSuiteInfo(channel.cipherSuite,=20&suite,=20= sizeof(suite));=0A+=09if=20(status=20!=3D=20SECSuccess)=0A+=09=09return=20= NULL;=0A+=0A+=09if=20(strcmp(attribute_name,=20"cipher")=20=3D=3D=200)=0A= +=09=09return=20suite.cipherSuiteName;=0A+=0A+=09if=20= (strcmp(attribute_name,=20"key_bits")=20=3D=3D=200)=0A+=09{=0A+=09=09= static=20char=20key_bits_str[8];=0A+=0A+=09=09snprintf(key_bits_str,=20= sizeof(key_bits_str),=20"%i",=20suite.effectiveKeyBits);=0A+=09=09return=20= key_bits_str;=0A+=09}=0A+=0A+=09if=20(strcmp(attribute_name,=20= "protocol")=20=3D=3D=200)=0A+=09{=0A+=09=09= switch(channel.protocolVersion)=0A+=09=09{=0A+#ifdef=20= SSL_LIBRARY_VERSION_TLS_1_3=0A+=09=09=09case=20= SSL_LIBRARY_VERSION_TLS_1_3:=0A+=09=09=09=09return=20"TLSv1.3";=0A= +#endif=0A+#ifdef=20SSL_LIBRARY_VERSION_TLS_1_2=0A+=09=09=09case=20= SSL_LIBRARY_VERSION_TLS_1_2:=0A+=09=09=09=09return=20"TLSv1.2";=0A= +#endif=0A+#ifdef=20SSL_LIBRARY_VERSION_TLS_1_1=0A+=09=09=09case=20= SSL_LIBRARY_VERSION_TLS_1_1:=0A+=09=09=09=09return=20"TLSv1.1";=0A= +#endif=0A+=09=09=09case=20SSL_LIBRARY_VERSION_TLS_1_0:=0A+=09=09=09=09= return=20"TLSv1.0";=0A+=09=09=09default:=0A+=09=09=09=09return=20= "unknown";=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20NSS=20disabled=20= support=20for=20compression=20in=20version=203.33,=20and=20it=20was=20= only=0A+=09=20*=20available=20for=20SSLv3=20at=20that=20point=20anyways,=20= so=20we=20can=20safely=20return=20off=0A+=09=20*=20here=20without=20= checking.=0A+=09=20*/=0A+=09if=20(strcmp(attribute_name,=20= "compression")=20=3D=3D=200)=0A+=09=09return=20"off";=0A+=0A+=09return=20= NULL;=0A+}=0A+=0A+static=20int=0A+ssl_protocol_version_to_nss(const=20= char=20*protocol)=0A+{=0A+=09if=20(pg_strcasecmp("TLSv1",=20protocol)=20= =3D=3D=200)=0A+=09=09return=20SSL_LIBRARY_VERSION_TLS_1_0;=0A+=0A+#ifdef=20= SSL_LIBRARY_VERSION_TLS_1_1=0A+=09if=20(pg_strcasecmp("TLSv1.1",=20= protocol)=20=3D=3D=200)=0A+=09=09return=20SSL_LIBRARY_VERSION_TLS_1_1;=0A= +#endif=0A+=0A+#ifdef=20SSL_LIBRARY_VERSION_TLS_1_2=0A+=09if=20= (pg_strcasecmp("TLSv1.2",=20protocol)=20=3D=3D=200)=0A+=09=09return=20= SSL_LIBRARY_VERSION_TLS_1_2;=0A+#endif=0A+=0A+#ifdef=20= SSL_LIBRARY_VERSION_TLS_1_3=0A+=09if=20(pg_strcasecmp("TLSv1.3",=20= protocol)=20=3D=3D=200)=0A+=09=09return=20SSL_LIBRARY_VERSION_TLS_1_3;=0A= +#endif=0A+=0A+=09return=20-1;=0A+}=0A+=0A+static=20bool=0A= +cert_database_has_CA(PGconn=20*conn)=0A+{=0A+=09CERTCertList=09=20=20=20= *certificates;=0A+=09bool=09=09=09=09hasCA;=0A+=0A+=09/*=0A+=09=20*=20If=20= the=20certificate=20database=20has=20a=20password=20we=20must=20provide=20= it,=20since=0A+=09=20*=20this=20API=20doesn't=20invoke=20the=20standard=20= password=20callback.=0A+=09=20*/=0A+=09if=20(has_password)=0A+=09=09= certificates=20=3D=20PK11_ListCerts(PK11CertListCA,=20= PQssl_passwd_cb(NULL,=20PR_FALSE,=20(void=20*)=20conn));=0A+=09else=0A+=09= =09certificates=20=3D=20PK11_ListCerts(PK11CertListCA,=20NULL);=0A+=09= hasCA=20=3D=20!CERT_LIST_EMPTY(certificates);=0A+=09= CERT_DestroyCertList(certificates);=0A+=0A+=09return=20hasCA;=0A+}=0A+=0A= +PQsslKeyPassHook_type_nss=0A+PQgetSSLKeyPassHook_nss(void)=0A+{=0A+=09= return=20PQsslKeyPassHook;=0A+}=0A+=0A+void=0A= +PQsetSSLKeyPassHook_nss(PQsslKeyPassHook_type_nss=20hook)=0A+{=0A+=09= PQsslKeyPassHook=20=3D=20hook;=0A+}=0A+=0A+/*=0A+=20*=20Supply=20a=20= password=20to=20decrypt=20a=20client=20certificate.=0A+=20*=0A+=20*=20= This=20must=20match=20NSS=20type=20PK11PasswordFunc.=0A+=20*/=0A+static=20= char=20*=0A+PQssl_passwd_cb(PK11SlotInfo=20*slot,=20PRBool=20retry,=20= void=20*arg)=0A+{=0A+=09has_password=20=3D=20true;=0A+=0A+=09if=20= (PQsslKeyPassHook)=0A+=09=09return=20PQsslKeyPassHook(slot,=20(PRBool)=20= retry,=20arg);=0A+=09else=0A+=09=09return=20= PQdefaultSSLKeyPassHook_nss(slot,=20retry,=20arg);=0A+}=0A+=0A+/*=0A+=20= *=20The=20default=20password=20handler=20callback.=0A+=20*/=0A+char=20*=0A= +PQdefaultSSLKeyPassHook_nss(PK11SlotInfo=20*slot,=20PRBool=20retry,=20= void=20*arg)=0A+{=0A+=09PGconn=20*conn=20=3D=20(PGconn=20*)=20arg;=0A+=0A= +=09/*=0A+=09=20*=20If=20the=20password=20didn't=20work=20the=20first=20= time=20there=20is=20no=20point=20in=20retrying=0A+=09=20*=20as=20it=20= hasn't=20changed.=0A+=09=20*/=0A+=09if=20(retry=20!=3D=20PR_TRUE=20&&=20= conn->sslpassword=20&&=20strlen(conn->sslpassword)=20>=200)=0A+=09=09= return=20PORT_Strdup(conn->sslpassword);=0A+=0A+=09return=20NULL;=0A+}=0A= diff=20--git=20a/src/interfaces/libpq/libpq-fe.h=20= b/src/interfaces/libpq/libpq-fe.h=0Aindex=203b6a9fbce3..1fc7e43cfd=20= 100644=0A---=20a/src/interfaces/libpq/libpq-fe.h=0A+++=20= b/src/interfaces/libpq/libpq-fe.h=0A@@=20-625,6=20+625,17=20@@=20extern=20= PQsslKeyPassHook_OpenSSL_type=20PQgetSSLKeyPassHook_OpenSSL(void);=0A=20= extern=20void=20= PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type=20hook);=0A=20= extern=20int=09PQdefaultSSLKeyPassHook_OpenSSL(char=20*buf,=20int=20= size,=20PGconn=20*conn);=0A=20=0A+/*=20=3D=3D=20in=20fe-secure-nss.c=20= =3D=3D=3D=20*/=0A+typedef=20struct=20PK11SlotInfoStr=20PK11SlotInfo;=0A= +typedef=20int=20PRIntn;=0A+typedef=20PRIntn=20PRBool;=0A+=0A+/*=20= Support=20for=20overriding=20sslpassword=20handling=20with=20a=20= callback.=20*/=0A+typedef=20char=20= *(*PQsslKeyPassHook_type_nss)(PK11SlotInfo=20*slot,=20PRBool=20retry,=20= void=20*arg);=0A+extern=20PQsslKeyPassHook_type_nss=20= PQgetSSLKeyPassHook_nss(void);=0A+extern=20void=20= PQsetSSLKeyPassHook_nss(PQsslKeyPassHook_type_nss=20hook);=0A+extern=20= char=20*PQdefaultSSLKeyPassHook_nss(PK11SlotInfo=20*slot,=20PRBool=20= retry,=20void=20*arg);=0A+=0A=20#ifdef=20__cplusplus=0A=20}=0A=20#endif=0A= diff=20--git=20a/src/interfaces/libpq/libpq-int.h=20= b/src/interfaces/libpq/libpq-int.h=0Aindex=201de91ae295..53602dc1a6=20= 100644=0A---=20a/src/interfaces/libpq/libpq-int.h=0A+++=20= b/src/interfaces/libpq/libpq-int.h=0A@@=20-485,6=20+485,11=20@@=20struct=20= pg_conn=0A=20=09=09=09=09=09=09=09=09=20*=20OpenSSL=20version=20changes=20= */=0A=20#endif=0A=20#endif=09=09=09=09=09=09=09/*=20USE_OPENSSL=20*/=0A+=0A= +#ifdef=20USE_NSS=0A+=09char=09=20=20=20*cert_database;=0A+=09void=09=20=20= =20*pr_fd;=0A+#endif=09=09=09=09=09=09=09/*=20USE_NSS=20*/=0A=20#endif=09= =09=09=09=09=09=09/*=20USE_SSL=20*/=0A=20=0A=20#ifdef=20ENABLE_GSS=0A= diff=20--git=20a/src/test/ssl/Makefile=20b/src/test/ssl/Makefile=0Aindex=20= 777ee39413..aa68b4175c=20100644=0A---=20a/src/test/ssl/Makefile=0A+++=20= b/src/test/ssl/Makefile=0A@@=20-14,6=20+14,7=20@@=20top_builddir=20=3D=20= ../../..=0A=20include=20$(top_builddir)/src/Makefile.global=0A=20=0A=20= export=20with_openssl=0A+export=20with_nss=0A=20=0A=20CERTIFICATES=20:=3D=20= server_ca=20server-cn-and-alt-names=20\=0A=20=09server-cn-only=20= server-single-alt-name=20server-multiple-alt-names=20\=0A@@=20-30,6=20= +31,27=20@@=20SSLFILES=20:=3D=20$(CERTIFICATES:%=3Dssl/%.key)=20= $(CERTIFICATES:%=3Dssl/%.crt)=20\=0A=20=09ssl/client+client_ca.crt=20= ssl/client-der.key=20\=0A=20=09ssl/client-encrypted-pem.key=20= ssl/client-encrypted-der.key=0A=20=0A+NSSFILES=20:=3D=20= ssl/nss/client_ca.crt.db=20\=0A+=09ssl/nss/server_ca.crt.db=20\=0A+=09= ssl/nss/root+server_ca.crt.db=20\=0A+=09ssl/nss/root+client_ca.crt.db=20= \=0A+=09ssl/nss/both-cas-1.crt.db=20\=0A+=09= ssl/nss/client.crt__client.key.db=20\=0A+=09= ssl/nss/client-revoked.crt__client-revoked.key.db=20\=0A+=09= ssl/nss/server-cn-only.crt__server-password.key.db=20\=0A+=09= ssl/nss/server-cn-only.crt__server-cn-only.key.db=20\=0A+=09= ssl/nss/root.crl.der=20\=0A+=09ssl/nss/server.crl.der=20\=0A+=09= ssl/nss/client.crl.der=20\=0A+=09= ssl/nss/server-multiple-alt-names.crt__server-multiple-alt-names.key.db=20= \=0A+=09= ssl/nss/server-single-alt-name.crt__server-single-alt-name.key.db=20\=0A= +=09ssl/nss/server-cn-and-alt-names.crt__server-cn-and-alt-names.key.db=20= \=0A+=09ssl/nss/server-no-names.crt__server-no-names.key.db=20\=0A+=09= ssl/nss/server-revoked.crt__server-revoked.key.db=20\=0A+=09= ssl/nss/root+client.crl.der=20\=0A+=09= ssl/nss/client+client_ca.crt__client.key.db=20\=0A+=09= ssl/nss/client.crt__client-encrypted-pem.key.db=0A+=0A=20#=20This=20= target=20re-generates=20all=20the=20key=20and=20certificate=20files.=20= Usually=20we=20just=0A=20#=20use=20the=20ones=20that=20are=20committed=20= to=20the=20tree=20without=20rebuilding=20them.=0A=20#=0A@@=20-37,6=20= +59,9=20@@=20SSLFILES=20:=3D=20$(CERTIFICATES:%=3Dssl/%.key)=20= $(CERTIFICATES:%=3Dssl/%.crt)=20\=0A=20#=0A=20sslfiles:=20$(SSLFILES)=0A=20= =0A+#=20Generate=20NSS=20certificate=20databases=20corresponding=20to=20= the=20OpenSSL=20certificates=0A+nssfiles:=20$(NSSFILES)=0A+=0A=20#=20= OpenSSL=20requires=20a=20directory=20to=20put=20all=20generated=20= certificates=20in.=20We=20don't=0A=20#=20use=20this=20for=20anything,=20= but=20we=20need=20a=20location.=0A=20ssl/new_certs_dir:=0A@@=20-64,6=20= +89,11=20@@=20ssl/%_ca.crt:=20ssl/%_ca.key=20%_ca.config=20= ssl/root_ca.crt=20ssl/new_certs_dir=0A=20=09rm=20ssl/temp_ca.crt=20= ssl/temp_ca_signed.crt=0A=20=09echo=20"01"=20>=20ssl/$*_ca.srl=0A=20=0A= +ssl/nss/%_ca.crt.db:=20ssl/%_ca.crt=0A+=09$(MKDIR_P)=20$@=0A+=09= certutil=20-d=20"sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20= "sql:$@"=20-A=20-n=20$*_ca.crt=20-i=20ssl/$*_ca.crt=20-t=20"CT,C,C"=0A+=0A= =20#=20Server=20certificates,=20signed=20by=20server=20CA:=0A=20= ssl/server-%.crt:=20ssl/server-%.key=20ssl/server_ca.crt=20= server-%.config=0A=20=09openssl=20req=20-new=20-key=20ssl/server-$*.key=20= -out=20ssl/server-$*.csr=20-config=20server-$*.config=0A@@=20-77,6=20= +107,74=20@@=20ssl/server-ss.crt:=20ssl/server-cn-only.key=20= ssl/server-cn-only.crt=20server-cn-only.=0A=20=09openssl=20x509=20-req=20= -days=2010000=20-in=20ssl/server-ss.csr=20-signkey=20= ssl/server-cn-only.key=20-out=20ssl/server-ss.crt=20=20-extensions=20= v3_req=20-extfile=20server-cn-only.config=0A=20=09rm=20ssl/server-ss.csr=0A= =20=0A+ssl/nss/server-cn-only.crt__server-password.key.db:=20= ssl/server-cn-only.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20= "sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -n=20server-cn-only.crt__server-password.key=20-i=20= ssl/server-cn-only.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20"CT,C,C"=0A+=09= certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20ssl/root_ca.crt=20= -t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20client_ca.crt=20= -i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20pkcs12=20-export=20= -out=20ssl/nss/server-password.pfx=20-inkey=20ssl/server-password.key=20= -in=20ssl/server-cn-only.crt=20-certfile=20ssl/server_ca.crt=20-passin=20= 'pass:secret1'=20-passout=20pass:=0A+=09pk12util=20-i=20= ssl/nss/server-password.pfx=20-d=20$@=20-W=20''=0A+=0A= +ssl/nss/server-cn-only.crt__server-cn-only.key.db:=20= ssl/server-cn-only.crt=20ssl/server-cn-only.key=0A+=09$(MKDIR_P)=20$@=0A= +=09certutil=20-d=20"sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20= "sql:$@"=20-A=20-n=20server-cn-only.crt__server-cn-only.key=20-i=20= ssl/server-cn-only.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20"CT,C,C"=0A+=09= openssl=20pkcs12=20-export=20-out=20ssl/nss/server-cn-only.pfx=20-inkey=20= ssl/server-cn-only.key=20-in=20ssl/server-cn-only.crt=20-certfile=20= ssl/server_ca.crt=20-passout=20pass:=0A+=09pk12util=20-i=20= ssl/nss/server-cn-only.pfx=20-d=20$@=20-W=20''=0A+=0A= +ssl/nss/server-multiple-alt-names.crt__server-multiple-alt-names.key.db:=20= ssl/server-multiple-alt-names.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20= -d=20"sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server-multiple-alt-names.crt__server-multiple-alt-names.key=20= -i=20ssl/server-multiple-alt-names.crt=20-t=20"CT,C,C"=0A+=09certutil=20= -d=20"sql:$@"=20-A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20= "CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20= ssl/root_ca.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20= pkcs12=20-export=20-out=20ssl/nss/server-multiple-alt-names.pfx=20-inkey=20= ssl/server-multiple-alt-names.key=20-in=20= ssl/server-multiple-alt-names.crt=20-certfile=20= ssl/server-multiple-alt-names.crt=20-passout=20pass:=0A+=09pk12util=20-i=20= ssl/nss/server-multiple-alt-names.pfx=20-d=20$@=20-W=20''=0A+=0A= +ssl/nss/server-single-alt-name.crt__server-single-alt-name.key.db:=20= ssl/server-single-alt-name.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20= "sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -n=20server-single-alt-name.crt__server-single-alt-name.key=20-i=20= ssl/server-single-alt-name.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20= "sql:$@"=20-A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20= "CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20= ssl/root_ca.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20= pkcs12=20-export=20-out=20ssl/nss/server-single-alt-name.pfx=20-inkey=20= ssl/server-single-alt-name.key=20-in=20ssl/server-single-alt-name.crt=20= -certfile=20ssl/server-single-alt-name.crt=20-passout=20pass:=0A+=09= pk12util=20-i=20ssl/nss/server-single-alt-name.pfx=20-d=20$@=20-W=20''=0A= +=0A= +ssl/nss/server-cn-and-alt-names.crt__server-cn-and-alt-names.key.db:=20= ssl/server-cn-and-alt-names.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20= -d=20"sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server-cn-and-alt-names.crt__server-cn-and-alt-names.key=20-i=20= ssl/server-cn-and-alt-names.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20= "sql:$@"=20-A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20= "CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20= ssl/root_ca.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20= pkcs12=20-export=20-out=20ssl/nss/server-cn-and-alt-names.pfx=20-inkey=20= ssl/server-cn-and-alt-names.key=20-in=20ssl/server-cn-and-alt-names.crt=20= -certfile=20ssl/server-cn-and-alt-names.crt=20-passout=20pass:=0A+=09= pk12util=20-i=20ssl/nss/server-cn-and-alt-names.pfx=20-d=20$@=20-W=20''=0A= +=0A+ssl/nss/server-no-names.crt__server-no-names.key.db:=20= ssl/server-no-names.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20= "sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -n=20server-no-names.crt__server-no-names.key=20-i=20= ssl/server-no-names.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20"CT,C,C"=0A+=09= certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20ssl/root_ca.crt=20= -t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20client_ca.crt=20= -i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20pkcs12=20-export=20= -out=20ssl/nss/server-no-names.pfx=20-inkey=20ssl/server-no-names.key=20= -in=20ssl/server-no-names.crt=20-certfile=20ssl/server-no-names.crt=20= -passout=20pass:=0A+=09pk12util=20-i=20ssl/nss/server-no-names.pfx=20-d=20= $@=20-W=20''=0A+=0A+ssl/nss/server-revoked.crt__server-revoked.key.db:=20= ssl/server-revoked.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20= "sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -n=20server-revoked.crt__server-revoked.key=20-i=20= ssl/server-revoked.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20server_ca.crt=20-i=20ssl/server_ca.crt=20-t=20"CT,C,C"=0A+=09= certutil=20-d=20"sql:$@"=20-A=20-n=20root_ca.crt=20-i=20ssl/root_ca.crt=20= -t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20client_ca.crt=20= -i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20pkcs12=20-export=20= -out=20ssl/nss/server-revoked.pfx=20-inkey=20ssl/server-revoked.key=20= -in=20ssl/server-revoked.crt=20-certfile=20ssl/server-revoked.crt=20= -passout=20pass:=0A+=09pk12util=20-i=20ssl/nss/server-revoked.pfx=20-d=20= $@=20-W=20''=0A+=0A=20#=20Password-protected=20version=20of=20= server-cn-only.key=0A=20ssl/server-password.key:=20= ssl/server-cn-only.key=0A=20=09openssl=20rsa=20-aes256=20-in=20$<=20-out=20= $@=20-passout=20'pass:secret1'=0A@@=20-88,6=20+186,27=20@@=20= ssl/client.crt:=20ssl/client.key=20ssl/client_ca.crt=0A=20=09openssl=20= x509=20-in=20ssl/temp.crt=20-out=20ssl/client.crt=20#=20to=20keep=20just=20= the=20PEM=20cert=0A=20=09rm=20ssl/client.csr=20ssl/temp.crt=0A=20=0A+#=20= Client=20certificate,=20signed=20by=20client=20CA=0A= +ssl/nss/client.crt__client.key.db:=20ssl/client.crt=0A+=09$(MKDIR_P)=20= $@=0A+=09certutil=20-d=20"sql:$@"=20-N=20--empty-password=0A+=09certutil=20= -d=20"sql:$@"=20-A=20-n=20client.crt__client.key=20-i=20ssl/client.crt=20= -t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20client_ca.crt=20= -i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20root+server_ca.crt=20-i=20ssl/root+server_ca.crt=20-t=20= "CT,C,C"=0A+=09openssl=20pkcs12=20-export=20-out=20ssl/nss/client.pfx=20= -inkey=20ssl/client.key=20-in=20ssl/client.crt=20-certfile=20= ssl/client_ca.crt=20-passout=20pass:=0A+=09pk12util=20-i=20= ssl/nss/client.pfx=20-d=20$@=20-W=20''=0A+=0A+#=20Client=20certificate=20= with=20encrypted=20key,=20signed=20by=20client=20CA=0A= +ssl/nss/client.crt__client-encrypted-pem.key.db:=20ssl/client.crt=0A+=09= $(MKDIR_P)=20$@=0A+=09echo=20'dUmmyP^#+'=20>=20$@.pass=0A+=09certutil=20= -d=20"sql:$@"=20-N=20-f=20$@.pass=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -f=20$@.pass=20-n=20client.crt__client-encrypted-pem.key=20-i=20= ssl/client.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-f=20= $@.pass=20-n=20client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A= +=09certutil=20-d=20"sql:$@"=20-A=20-f=20$@.pass=20-n=20= root+server_ca.crt=20-i=20ssl/root+server_ca.crt=20-t=20"CT,C,C"=0A+=09= openssl=20pkcs12=20-export=20-out=20ssl/nss/client-encrypted-pem.pfx=20= -inkey=20ssl/client-encrypted-pem.key=20-in=20ssl/client.crt=20-certfile=20= ssl/client_ca.crt=20-passin=20pass:'dUmmyP^#+'=20-passout=20= pass:'dUmmyP^#+'=0A+=09pk12util=20-i=20ssl/nss/client-encrypted-pem.pfx=20= -d=20$@=20-W=20'dUmmyP^#+'=20-k=20$@.pass=0A+=0A=20#=20Another=20client=20= certificate,=20signed=20by=20the=20client=20CA.=20This=20one=20is=20= revoked.=0A=20ssl/client-revoked.crt:=20ssl/client-revoked.key=20= ssl/client_ca.crt=20client.config=0A=20=09openssl=20req=20-new=20-key=20= ssl/client-revoked.key=20-out=20ssl/client-revoked.csr=20-config=20= client.config=0A@@=20-95,6=20+214,14=20@@=20ssl/client-revoked.crt:=20= ssl/client-revoked.key=20ssl/client_ca.crt=20client.config=0A=20=09= openssl=20x509=20-in=20ssl/temp.crt=20-out=20ssl/client-revoked.crt=20#=20= to=20keep=20just=20the=20PEM=20cert=0A=20=09rm=20ssl/client-revoked.csr=20= ssl/temp.crt=0A=20=0A+ssl/nss/client-revoked.crt__client-revoked.key.db:=20= ssl/client-revoked.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20= "sql:$@"=20-N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20= -n=20client-revoked.crt__client-revoked.key=20-i=20= ssl/client-revoked.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20= -A=20-n=20client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20"CT,C,C"=0A+=09= openssl=20pkcs12=20-export=20-out=20ssl/nss/client-revoked.pfx=20-inkey=20= ssl/client-revoked.key=20-in=20ssl/client-revoked.crt=20-certfile=20= ssl/client_ca.crt=20-passout=20pass:=0A+=09pk12util=20-i=20= ssl/nss/client-revoked.pfx=20-d=20$@=20-W=20''=0A+=0A=20#=20Convert=20= the=20key=20to=20DER,=20to=20test=20our=20behaviour=20there=20too=0A=20= ssl/client-der.key:=20ssl/client.key=0A=20=09openssl=20rsa=20-in=20= ssl/client.key=20-outform=20DER=20-out=20ssl/client-der.key=0A@@=20= -112,6=20+239,13=20@@=20ssl/client-encrypted-der.key:=20ssl/client.key=0A= =20ssl/both-cas-1.crt:=20ssl/root_ca.crt=20ssl/client_ca.crt=20= ssl/server_ca.crt=0A=20=09cat=20$^=20>=20$@=0A=20=0A= +ssl/nss/both-cas-1.crt.db:=20ssl/root_ca.crt=20ssl/client_ca.crt=20= ssl/server_ca.crt=0A+=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20"sql:$@"=20= -N=20--empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= root_ca.crt=20-i=20ssl/root_ca.crt=20-t=20"CT,C,C"=0A+=09certutil=20-d=20= "sql:$@"=20-A=20-n=20client_ca.crt=20-i=20ssl/client_ca.crt=20-t=20= "CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20server_ca.crt=20-i=20= ssl/server_ca.crt=20-t=20"CT,C,C"=0A+=0A=20#=20The=20same,=20but=20the=20= certs=20are=20in=20different=20order=0A=20ssl/both-cas-2.crt:=20= ssl/root_ca.crt=20ssl/server_ca.crt=20ssl/client_ca.crt=0A=20=09cat=20$^=20= >=20$@=0A@@=20-127,19=20+261,41=20@@=20ssl/root+client_ca.crt:=20= ssl/root_ca.crt=20ssl/client_ca.crt=0A=20ssl/client+client_ca.crt:=20= ssl/client.crt=20ssl/client_ca.crt=0A=20=09cat=20$^=20>=20$@=0A=20=0A+#=20= Client=20certificate,=20signed=20by=20client=20CA=0A= +ssl/nss/client+client_ca.crt__client.key.db:=20ssl/client+client_ca.crt=0A= +=09$(MKDIR_P)=20$@=0A+=09certutil=20-d=20"sql:$@"=20-N=20= --empty-password=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= client+client_ca.crt__client.key=20-i=20ssl/client+client_ca.crt=20-t=20= "CT,C,C"=0A+=09certutil=20-d=20"sql:$@"=20-A=20-n=20= client.crt__client.key=20-i=20ssl/client.crt=20-t=20"CT,C,C"=0A+=09= certutil=20-d=20"sql:$@"=20-A=20-n=20root+server_ca.crt=20-i=20= ssl/root+server_ca.crt=20-t=20"CT,C,C"=0A+=09openssl=20pkcs12=20-export=20= -out=20ssl/nss/client.pfx=20-inkey=20ssl/client.key=20-in=20= ssl/client.crt=20-certfile=20ssl/client_ca.crt=20-passout=20pass:=0A+=09= pk12util=20-i=20ssl/nss/client.pfx=20-d=20$@=20-W=20''=0A+=0A=20####=20= CRLs=0A=20=0A=20ssl/client.crl:=20ssl/client-revoked.crt=0A=20=09openssl=20= ca=20-config=20cas.config=20-name=20client_ca=20-revoke=20= ssl/client-revoked.crt=0A=20=09openssl=20ca=20-config=20cas.config=20= -name=20client_ca=20-gencrl=20-out=20ssl/client.crl=0A=20=0A= +ssl/nss/client.crl.der:=20ssl/client.crl=0A+=09openssl=20crl=20-in=20$^=20= -outform=20der=20-out=20$@=0A+=0A=20ssl/server.crl:=20= ssl/server-revoked.crt=0A=20=09openssl=20ca=20-config=20cas.config=20= -name=20server_ca=20-revoke=20ssl/server-revoked.crt=0A=20=09openssl=20= ca=20-config=20cas.config=20-name=20server_ca=20-gencrl=20-out=20= ssl/server.crl=0A=20=0A+ssl/nss/server.crl.der:=20ssl/server.crl=0A+=09= openssl=20crl=20-in=20$^=20-outform=20der=20-out=20$@=0A+=0A=20= ssl/root.crl:=20ssl/root_ca.crt=0A=20=09openssl=20ca=20-config=20= cas.config=20-name=20root_ca=20-gencrl=20-out=20ssl/root.crl=0A=20=0A= +ssl/nss/root.crl.der:=20ssl/root.crl=0A+=09openssl=20crl=20-in=20$^=20= -outform=20der=20-out=20$@=0A+=0A+ssl/nss/root+client.crl.der:=20= ssl/root+client.crl=0A+=09openssl=20crl=20-in=20$^=20-outform=20der=20= -out=20$@=0A+=0A=20#=20If=20a=20CRL=20is=20used,=20OpenSSL=20requires=20= a=20CRL=20file=20for=20*all*=20the=20CAs=20in=20the=0A=20#=20chain,=20= even=20if=20some=20of=20them=20are=20empty.=0A=20ssl/root+server.crl:=20= ssl/root.crl=20ssl/server.crl=0A@@=20-154,6=20+310,7=20@@=20= sslfiles-clean:=0A=20clean=20distclean=20maintainer-clean:=0A=20=09rm=20= -rf=20tmp_check=0A=20=09rm=20-rf=20ssl/*.old=20ssl/new_certs_dir=20= ssl/client*_tmp.key=0A+=09rm=20-rf=20ssl/nss=0A=20=0A=20#=20Doesn't=20= depend=20on=20$(SSLFILES)=20because=20we=20don't=20rebuild=20them=20by=20= default=0A=20check:=0Adiff=20--git=20a/src/test/ssl/t/001_ssltests.pl=20= b/src/test/ssl/t/001_ssltests.pl=0Aindex=20c0680f39d6..dbbe94a645=20= 100644=0A---=20a/src/test/ssl/t/001_ssltests.pl=0A+++=20= b/src/test/ssl/t/001_ssltests.pl=0A@@=20-4,15=20+4,22=20@@=20use=20= PostgresNode;=0A=20use=20TestLib;=0A=20use=20Test::More;=0A=20=0A-use=20= File::Copy;=0A-=0A=20use=20FindBin;=0A=20use=20lib=20$FindBin::RealBin;=0A= =20=0A-use=20SSLServer;=0A+use=20SSL::Server;=0A+=0A+my=20$openssl;=0A= +my=20$nss;=0A=20=0A=20if=20($ENV{with_openssl}=20eq=20'yes')=0A=20{=0A+=09= $openssl=20=3D=201;=0A+=09plan=20tests=20=3D>=2093;=0A+}=0A+elsif=20= ($ENV{with_nss}=20eq=20'yes')=0A+{=0A+=09$nss=20=3D=201;=0A=20=09plan=20= tests=20=3D>=2093;=0A=20}=0A=20else=0A@@=20-32,32=20+39,6=20@@=20my=20= $SERVERHOSTCIDR=20=3D=20'127.0.0.1/32';=0A=20#=20Allocation=20of=20base=20= connection=20string=20shared=20among=20multiple=20tests.=0A=20my=20= $common_connstr;=0A=20=0A-#=20The=20client's=20private=20key=20must=20= not=20be=20world-readable,=20so=20take=20a=20copy=0A-#=20of=20the=20key=20= stored=20in=20the=20code=20tree=20and=20update=20its=20permissions.=0A-#=0A= -#=20This=20changes=20ssl/client.key=20to=20ssl/client_tmp.key=20etc=20= for=20the=20rest=0A-#=20of=20the=20tests.=0A-my=20@keys=20=3D=20(=0A-=09= "client",=20=20=20=20=20"client-revoked",=0A-=09"client-der",=20= "client-encrypted-pem",=0A-=09"client-encrypted-der");=0A-foreach=20my=20= $key=20(@keys)=0A-{=0A-=09copy("ssl/${key}.key",=20"ssl/${key}_tmp.key")=0A= -=09=20=20or=20die=0A-=09=20=20"couldn't=20copy=20ssl/${key}.key=20to=20= ssl/${key}_tmp.key=20for=20permissions=20change:=20$!";=0A-=09chmod=20= 0600,=20"ssl/${key}_tmp.key"=0A-=09=20=20or=20die=20"failed=20to=20= change=20permissions=20on=20ssl/${key}_tmp.key:=20$!";=0A-}=0A-=0A-#=20= Also=20make=20a=20copy=20of=20that=20explicitly=20world-readable.=20=20= We=20can't=0A-#=20necessarily=20rely=20on=20the=20file=20in=20the=20= source=20tree=20having=20those=0A-#=20permissions.=20=20Add=20it=20to=20= @keys=20to=20include=20it=20in=20the=20final=20clean=0A-#=20up=20phase.=0A= -copy("ssl/client.key",=20"ssl/client_wrongperms_tmp.key");=0A-chmod=20= 0644,=20"ssl/client_wrongperms_tmp.key";=0A-push=20@keys,=20= 'client_wrongperms';=0A-=0A=20####=20Set=20up=20the=20server.=0A=20=0A=20= note=20"setting=20up=20data=20directory";=0A@@=20-72,32=20+53,27=20@@=20= $node->start;=0A=20=0A=20#=20Run=20this=20before=20we=20lock=20down=20= access=20below.=0A=20my=20$result=20=3D=20$node->safe_psql('postgres',=20= "SHOW=20ssl_library");=0A-is($result,=20'OpenSSL',=20'ssl_library=20= parameter');=0A+is($result,=20SSL::Server::ssl_library(),=20'ssl_library=20= parameter');=0A=20=0A=20configure_test_server_for_ssl($node,=20= $SERVERHOSTADDR,=20$SERVERHOSTCIDR,=0A=20=09'trust');=0A=20=0A=20note=20= "testing=20password-protected=20keys";=0A=20=0A-open=20my=20$sslconf,=20= '>',=20$node->data_dir=20.=20"/sslconfig.conf";=0A-print=20$sslconf=20= "ssl=3Don\n";=0A-print=20$sslconf=20= "ssl_cert_file=3D'server-cn-only.crt'\n";=0A-print=20$sslconf=20= "ssl_key_file=3D'server-password.key'\n";=0A-print=20$sslconf=20= "ssl_passphrase_command=3D'echo=20wrongpassword'\n";=0A-close=20= $sslconf;=0A-=0A-command_fails(=0A-=09[=20'pg_ctl',=20'-D',=20= $node->data_dir,=20'-l',=20$node->logfile,=20'restart'=20],=0A-=09= 'restart=20fails=20with=20password-protected=20key=20file=20with=20wrong=20= password');=0A-$node->_update_pid(0);=0A-=0A-open=20$sslconf,=20'>',=20= $node->data_dir=20.=20"/sslconfig.conf";=0A-print=20$sslconf=20= "ssl=3Don\n";=0A-print=20$sslconf=20= "ssl_cert_file=3D'server-cn-only.crt'\n";=0A-print=20$sslconf=20= "ssl_key_file=3D'server-password.key'\n";=0A-print=20$sslconf=20= "ssl_passphrase_command=3D'echo=20secret1'\n";=0A-close=20$sslconf;=0A= +SKIP:=0A+{=0A+=09skip=20"Certificate=20passphrases=20aren't=20checked=20= on=20server=20restart=20in=20NSS",=201=20if=20($nss);=0A+=0A+=09= switch_server_cert($node,=20'server-cn-only',=20'root+client_ca',=20= 'server-password',=0A+=09=09'echo=20wrongpassword');=0A+=09= command_fails(=0A+=09=09[=20'pg_ctl',=20'-D',=20$node->data_dir,=20'-l',=20= $node->logfile,=20'restart'=20],=0A+=09=09'restart=20fails=20with=20= password-protected=20key=20file=20with=20wrong=20password');=0A+=09= $node->_update_pid(0);=0A+}=0A=20=0A+switch_server_cert($node,=20= 'server-cn-only',=20'root+client_ca',=20'server-password',=0A+=09= 'echo=3Dsecret1');=0A=20command_ok(=0A=20=09[=20'pg_ctl',=20'-D',=20= $node->data_dir,=20'-l',=20$node->logfile,=20'restart'=20],=0A=20=09= 'restart=20succeeds=20with=20password-protected=20key=20file');=0A@@=20= -149,44=20+125,44=20@@=20test_connect_ok(=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A=20=09"sslrootcert=3Dinvalid=20sslmode=3Dverify-ca",=0A= -=09qr/root=20certificate=20file=20"invalid"=20does=20not=20exist/,=0A+=09= qr/root=20certificate=20file=20"invalid"=20does=20not=20exist|could=20= not=20connect=20to=20server/,=0A=20=09"connect=20without=20server=20root=20= cert=20sslmode=3Dverify-ca");=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A=20=09"sslrootcert=3Dinvalid=20sslmode=3Dverify-full",=0A= -=09qr/root=20certificate=20file=20"invalid"=20does=20not=20exist/,=0A+=09= qr/root=20certificate=20file=20"invalid"=20does=20not=20exist|could=20= not=20connect=20to=20server/,=0A=20=09"connect=20without=20server=20root=20= cert=20sslmode=3Dverify-full");=0A=20=0A=20#=20Try=20with=20wrong=20root=20= cert,=20should=20fail.=20(We're=20using=20the=20client=20CA=20as=20the=0A= =20#=20root,=20but=20the=20server's=20key=20is=20signed=20by=20the=20= server=20CA.)=0A=20test_connect_fails($common_connstr,=0A-=09= "sslrootcert=3Dssl/client_ca.crt=20sslmode=3Drequire",=0A+=09= "sslrootcert=3Dssl/client_ca.crt=20sslmode=3Drequire=20= cert_database=3Dssl/nss/client_ca.crt.db",=0A=20=09qr/SSL=20error/,=20= "connect=20with=20wrong=20server=20root=20cert=20sslmode=3Drequire");=0A=20= test_connect_fails($common_connstr,=0A-=09"sslrootcert=3Dssl/client_ca.crt= =20sslmode=3Dverify-ca",=0A+=09"sslrootcert=3Dssl/client_ca.crt=20= sslmode=3Dverify-ca=20cert_database=3Dssl/nss/client_ca.crt.db",=0A=20=09= qr/SSL=20error/,=20"connect=20with=20wrong=20server=20root=20cert=20= sslmode=3Dverify-ca");=0A=20test_connect_fails($common_connstr,=0A-=09= "sslrootcert=3Dssl/client_ca.crt=20sslmode=3Dverify-full",=0A+=09= "sslrootcert=3Dssl/client_ca.crt=20sslmode=3Dverify-full=20= cert_database=3Dssl/nss/client_ca.crt.db",=0A=20=09qr/SSL=20error/,=20= "connect=20with=20wrong=20server=20root=20cert=20sslmode=3Dverify-full");=0A= =20=0A=20#=20Try=20with=20just=20the=20server=20CA's=20cert.=20This=20= fails=20because=20the=20root=20file=0A=20#=20must=20contain=20the=20= whole=20chain=20up=20to=20the=20root=20CA.=0A=20= test_connect_fails($common_connstr,=0A-=09"sslrootcert=3Dssl/server_ca.crt= =20sslmode=3Dverify-ca",=0A+=09"sslrootcert=3Dssl/server_ca.crt=20= sslmode=3Dverify-ca=20cert_database=3Dssl/nss/server_ca.crt.db",=0A=20=09= qr/SSL=20error/,=20"connect=20with=20server=20CA=20cert,=20without=20= root=20CA");=0A=20=0A=20#=20And=20finally,=20with=20the=20correct=20root=20= cert.=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"connect=20with=20= correct=20server=20CA=20cert=20file=20sslmode=3Drequire");=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"connect=20with=20= correct=20server=20CA=20cert=20file=20sslmode=3Dverify-ca");=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-full",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-full=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"connect=20with=20= correct=20server=20CA=20cert=20file=20sslmode=3Dverify-full");=0A=20=0A=20= #=20Test=20with=20cert=20root=20file=20that=20contains=20two=20= certificates.=20The=20client=20should=0A@@=20-195,36=20+171,42=20@@=20= test_connect_ok(=0A=20=09$common_connstr,=0A=20=09= "sslrootcert=3Dssl/both-cas-1.crt=20sslmode=3Dverify-ca",=0A=20=09"cert=20= root=20file=20that=20contains=20two=20certificates,=20order=201");=0A= -test_connect_ok(=0A-=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/both-cas-2.crt=20sslmode=3Dverify-ca",=0A-=09"cert=20= root=20file=20that=20contains=20two=20certificates,=20order=202");=0A=20=0A= +#=20How=20about=20import=20the=20both-file=20into=20a=20database?=0A= +SKIP:=0A+{=0A+=09skip=20"CA=20ordering=20is=20irrelevant=20in=20NSS=20= databases=20",=201=20if=20($nss);=0A+=0A+=09test_connect_ok(=0A+=09=09= $common_connstr,=0A+=09=09"sslrootcert=3Dssl/both-cas-2.crt=20= sslmode=3Dverify-ca",=0A+=09=09"cert=20root=20file=20that=20contains=20= two=20certificates,=20order=202");=0A+}=0A=20#=20CRL=20tests=0A=20=0A=20= #=20Invalid=20CRL=20filename=20is=20the=20same=20as=20no=20CRL,=20= succeeds=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= sslcrl=3Dinvalid",=0A+=09"sslrootcert=3Dssl/root+server_ca.crt=20= sslmode=3Dverify-ca=20sslcrl=3Dinvalid=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"sslcrl=20option=20= with=20invalid=20file=20name");=0A=20=0A=20#=20A=20CRL=20belonging=20to=20= a=20different=20CA=20is=20not=20accepted,=20fails=0A=20= test_connect_fails(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= sslcrl=3Dssl/client.crl",=0A+=09"sslrootcert=3Dssl/root+server_ca.crt=20= sslmode=3Dverify-ca=20sslcrl=3Dssl/client.crl.der=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09qr/SSL=20error/,=0A= =20=09"CRL=20belonging=20to=20a=20different=20CA");=0A=20=0A=20#=20With=20= the=20correct=20CRL,=20succeeds=20(this=20cert=20is=20not=20revoked)=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= sslcrl=3Dssl/root+server.crl",=0A+=09"sslrootcert=3Dssl/root+server_ca.crt= =20sslmode=3Dverify-ca=20sslcrl=3Dssl/root+server.crl.der=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"CRL=20with=20a=20= non-revoked=20cert");=0A=20=0A=20#=20Check=20that=20connecting=20with=20= verify-full=20fails,=20when=20the=20hostname=20doesn't=0A=20#=20match=20= the=20hostname=20in=20the=20server's=20certificate.=0A=20$common_connstr=20= =3D=0A-=20=20"user=3Dssltestuser=20dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR";=0A+=20= =20"user=3Dssltestuser=20dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/root+server_ca.crt.db";=0A=20=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A@@=20-237,14=20+219,14=20@@=20= test_connect_ok(=0A=20test_connect_fails(=0A=20=09$common_connstr,=0A=20=09= "sslmode=3Dverify-full=20host=3Dwronghost.test",=0A-=09qr/\Qserver=20= certificate=20for=20"common-name.pg-ssltest.test"=20does=20not=20match=20= host=20name=20"wronghost.test"\E/,=0A+=09qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A= =20=09"mismatch=20between=20host=20name=20and=20server=20certificate=20= sslmode=3Dverify-full");=0A=20=0A=20#=20Test=20Subject=20Alternative=20= Names.=0A=20switch_server_cert($node,=20'server-multiple-alt-names');=0A=20= =0A=20$common_connstr=20=3D=0A-=20=20"user=3Dssltestuser=20= dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= sslmode=3Dverify-full";=0A+=20=20"user=3Dssltestuser=20dbname=3Dtrustdb=20= sslcert=3Dinvalid=20sslrootcert=3Dssl/root+server_ca.crt=20= hostaddr=3D$SERVERHOSTADDR=20sslmode=3Dverify-full=20= cert_database=3Dssl/nss/root+server_ca.crt.db";=0A=20=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A@@=20-262,12=20+244,12=20@@=20= test_connect_ok(=0A=20test_connect_fails(=0A=20=09$common_connstr,=0A=20=09= "host=3Dwronghost.alt-name.pg-ssltest.test",=0A-=09qr/\Qserver=20= certificate=20for=20"dns1.alt-name.pg-ssltest.test"=20(and=202=20other=20= names)=20does=20not=20match=20host=20name=20= "wronghost.alt-name.pg-ssltest.test"\E/,=0A+=09= qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A=20=09"host=20name=20not=20matching=20= with=20X.509=20Subject=20Alternative=20Names");=0A=20test_connect_fails(=0A= =20=09$common_connstr,=0A=20=09= "host=3Ddeep.subdomain.wildcard.pg-ssltest.test",=0A-=09qr/\Qserver=20= certificate=20for=20"dns1.alt-name.pg-ssltest.test"=20(and=202=20other=20= names)=20does=20not=20match=20host=20name=20= "deep.subdomain.wildcard.pg-ssltest.test"\E/,=0A+=09= qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A=20=09"host=20name=20not=20matching=20= with=20X.509=20Subject=20Alternative=20Names=20wildcard");=0A=20=0A=20#=20= Test=20certificate=20with=20a=20single=20Subject=20Alternative=20Name.=20= (this=20gives=20a=0A@@=20-275,7=20+257,7=20@@=20test_connect_fails(=0A=20= switch_server_cert($node,=20'server-single-alt-name');=0A=20=0A=20= $common_connstr=20=3D=0A-=20=20"user=3Dssltestuser=20dbname=3Dtrustdb=20= sslcert=3Dinvalid=20sslrootcert=3Dssl/root+server_ca.crt=20= hostaddr=3D$SERVERHOSTADDR=20sslmode=3Dverify-full";=0A+=20=20= "user=3Dssltestuser=20dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= sslmode=3Dverify-full=20cert_database=3Dssl/nss/root+server_ca.crt.db";=0A= =20=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A@@=20-285,12=20= +267,12=20@@=20test_connect_ok(=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A=20=09"host=3Dwronghost.alt-name.pg-ssltest.test",=0A= -=09qr/\Qserver=20certificate=20for=20"single.alt-name.pg-ssltest.test"=20= does=20not=20match=20host=20name=20= "wronghost.alt-name.pg-ssltest.test"\E/,=0A+=09= qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A=20=09"host=20name=20not=20matching=20= with=20a=20single=20X.509=20Subject=20Alternative=20Name");=0A=20= test_connect_fails(=0A=20=09$common_connstr,=0A=20=09= "host=3Ddeep.subdomain.wildcard.pg-ssltest.test",=0A-=09qr/\Qserver=20= certificate=20for=20"single.alt-name.pg-ssltest.test"=20does=20not=20= match=20host=20name=20"deep.subdomain.wildcard.pg-ssltest.test"\E/,=0A+=09= qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A=20=09"host=20name=20not=20matching=20= with=20a=20single=20X.509=20Subject=20Alternative=20Name=20wildcard"=0A=20= );=0A=20=0A@@=20-299,7=20+281,7=20@@=20test_connect_fails(=0A=20= switch_server_cert($node,=20'server-cn-and-alt-names');=0A=20=0A=20= $common_connstr=20=3D=0A-=20=20"user=3Dssltestuser=20dbname=3Dtrustdb=20= sslcert=3Dinvalid=20sslrootcert=3Dssl/root+server_ca.crt=20= hostaddr=3D$SERVERHOSTADDR=20sslmode=3Dverify-full";=0A+=20=20= "user=3Dssltestuser=20dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= sslmode=3Dverify-full=20cert_database=3Dssl/nss/root+server_ca.crt.db";=0A= =20=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A@@=20-312,14=20= +294,14=20@@=20test_connect_ok(=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A=20=09"host=3Dcommon-name.pg-ssltest.test",=0A-=09= qr/\Qserver=20certificate=20for=20"dns1.alt-name.pg-ssltest.test"=20(and=20= 1=20other=20name)=20does=20not=20match=20host=20name=20= "common-name.pg-ssltest.test"\E/,=0A+=09qr/SSL_ERROR_BAD_CERT_DOMAIN/,=0A= =20=09"certificate=20with=20both=20a=20CN=20and=20SANs=20ignores=20CN");=0A= =20=0A=20#=20Finally,=20test=20a=20server=20certificate=20that=20has=20= no=20CN=20or=20SANs.=20Of=20course,=20that's=0A=20#=20not=20a=20very=20= sensible=20certificate,=20but=20libpq=20should=20handle=20it=20= gracefully.=0A=20switch_server_cert($node,=20'server-no-names');=0A=20= $common_connstr=20=3D=0A-=20=20"user=3Dssltestuser=20dbname=3Dtrustdb=20= sslcert=3Dinvalid=20sslrootcert=3Dssl/root+server_ca.crt=20= hostaddr=3D$SERVERHOSTADDR";=0A+=20=20"user=3Dssltestuser=20= dbname=3Dtrustdb=20sslcert=3Dinvalid=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/root+server_ca.crt.db";=0A=20=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A@@=20-328,7=20+310,7=20@@=20= test_connect_ok(=0A=20test_connect_fails(=0A=20=09$common_connstr,=0A=20=09= "sslmode=3Dverify-full=20host=3Dcommon-name.pg-ssltest.test",=0A-=09= qr/could=20not=20get=20server's=20host=20name=20from=20server=20= certificate/,=0A+=09qr/could=20not=20get=20server's=20host=20name=20from=20= server=20certificate|SSL_ERROR_BAD_CERT_DOMAIN/,=0A=20=09"server=20= certificate=20without=20CN=20or=20SANs=20sslmode=3Dverify-full");=0A=20=0A= =20#=20Test=20that=20the=20CRL=20works=0A@@=20-340,11=20+322,11=20@@=20= $common_connstr=20=3D=0A=20#=20Without=20the=20CRL,=20succeeds.=20With=20= it,=20fails.=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"connects=20= without=20client-side=20CRL");=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A-=09"sslrootcert=3Dssl/root+server_ca.crt=20= sslmode=3Dverify-ca=20sslcrl=3Dssl/root+server.crl",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Dverify-ca=20= sslcrl=3Dssl/nss/server.crl.der=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09qr/SSL=20error/,=0A= =20=09"does=20not=20connect=20with=20client-side=20CRL");=0A=20=0A@@=20= -365,21=20+347,21=20@@=20command_like(=0A=20#=20Test=20min/max=20SSL=20= protocol=20versions.=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3DTLSv1.2=20ssl_max_protocol_version=3DTLSv1.2",=0A= +=09"sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3DTLSv1.2=20ssl_max_protocol_version=3DTLSv1.2=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09"connection=20= success=20with=20correct=20range=20of=20TLS=20protocol=20versions");=0A=20= test_connect_fails(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3DTLSv1.2=20ssl_max_protocol_version=3DTLSv1.1",=0A= +=09"sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3DTLSv1.2=20ssl_max_protocol_version=3DTLSv1.1=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09qr/invalid=20SSL=20= protocol=20version=20range/,=0A=20=09"connection=20failure=20with=20= incorrect=20range=20of=20TLS=20protocol=20versions");=0A=20= test_connect_fails(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3Dincorrect_tls",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_min_protocol_version=3Dincorrect_tls=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09qr/invalid=20= ssl_min_protocol_version=20value/,=0A=20=09"connection=20failure=20with=20= an=20incorrect=20SSL=20protocol=20minimum=20bound");=0A=20= test_connect_fails(=0A=20=09$common_connstr,=0A-=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_max_protocol_version=3Dincorrect_tls",=0A+=09= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= ssl_max_protocol_version=3Dincorrect_tls=20= cert_database=3Dssl/nss/root+server_ca.crt.db",=0A=20=09qr/invalid=20= ssl_max_protocol_version=20value/,=0A=20=09"connection=20failure=20with=20= an=20incorrect=20SSL=20protocol=20maximum=20bound");=0A=20=0A@@=20-390,7=20= +372,7=20@@=20test_connect_fails(=0A=20note=20"running=20server=20= tests";=0A=20=0A=20$common_connstr=20=3D=0A-=20=20= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dcertdb=20hostaddr=3D$SERVERHOSTADDR";=0A+=20=20= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dcertdb=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/client.crt__client.key.db";=0A=20=0A=20#=20no=20= client=20cert=0A=20test_connect_fails(=0A@@=20-402,36=20+384,47=20@@=20= test_connect_fails(=0A=20#=20correct=20client=20cert=20in=20unencrypted=20= PEM=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "user=3Dssltestuser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client_tmp.key",=0A+=09"user=3Dssltestuser=20= sslcert=3Dclient.crt__client.key=20sslkey=3Dssl/client_tmp.key",=0A=20=09= "certificate=20authorization=20succeeds=20with=20correct=20client=20cert=20= in=20PEM=20format"=0A=20);=0A=20=0A+$common_connstr=20=3D=0A+=20=20= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dcertdb=20hostaddr=3D$SERVERHOSTADDR";=0A+=0A+SKIP:=0A+{=0A+=09= skip=20"NSS=20database=20not=20implemented=20in=20the=20Makefile",=201=20= if=20($nss);=0A=20#=20correct=20client=20cert=20in=20unencrypted=20DER=0A= =20test_connect_ok(=0A=20=09$common_connstr,=0A=20=09"user=3Dssltestuser=20= sslcert=3Dssl/client.crt=20sslkey=3Dssl/client-der_tmp.key",=0A=20=09= "certificate=20authorization=20succeeds=20with=20correct=20client=20cert=20= in=20DER=20format"=0A=20);=0A+}=0A=20=0A=20#=20correct=20client=20cert=20= in=20encrypted=20PEM=0A=20test_connect_ok(=0A=20=09$common_connstr,=0A-=09= "user=3Dssltestuser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client-encrypted-pem_tmp.key=20sslpassword=3D'dUmmyP^#+'",=0A= +=09"user=3Dssltestuser=20sslcert=3Dclient.crt__client-encrypted-pem.key=20= sslkey=3Dssl/client-encrypted-pem_tmp.key=20sslpassword=3D'dUmmyP^#+'=20= cert_database=3Dssl/nss/client.crt__client-encrypted-pem.key.db",=0A=20=09= "certificate=20authorization=20succeeds=20with=20correct=20client=20cert=20= in=20encrypted=20PEM=20format"=0A=20);=0A=20=0A+SKIP:=0A+{=0A+=09skip=20= "NSS=20database=20not=20implemented=20in=20the=20Makefile",=201=20if=20= ($nss);=0A=20#=20correct=20client=20cert=20in=20encrypted=20DER=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A=20=09"user=3Dssltestuser=20= sslcert=3Dssl/client.crt=20sslkey=3Dssl/client-encrypted-der_tmp.key=20= sslpassword=3D'dUmmyP^#+'",=0A=20=09"certificate=20authorization=20= succeeds=20with=20correct=20client=20cert=20in=20encrypted=20DER=20= format"=0A=20);=0A+}=0A=20=0A=20#=20correct=20client=20cert=20in=20= encrypted=20PEM=20with=20wrong=20password=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A-=09"user=3Dssltestuser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client-encrypted-pem_tmp.key=20sslpassword=3D'wrong'",=0A-=09= qr!\Qprivate=20key=20file=20"ssl/client-encrypted-pem_tmp.key":=20bad=20= decrypt\E!,=0A+=09"user=3Dssltestuser=20= sslcert=3Dclient.crt__client-encrypted-pem.key=20= sslkey=3Dssl/client-encrypted-pem_tmp.key=20sslpassword=3D'wrong'=20= cert_database=3Dssl/nss/client.crt__client-encrypted-pem.key.db",=0A+=09= qr!connection=20requires=20a=20valid=20client=20certificate|\Qprivate=20= key=20file=20"ssl/client-encrypted-pem_tmp.key":=20bad=20decrypt\E!,=0A=20= =09"certificate=20authorization=20fails=20with=20correct=20client=20cert=20= and=20wrong=20password=20in=20encrypted=20PEM=20format"=0A=20);=0A=20=0A= @@=20-471,18=20+464,19=20@@=20command_like(=0A=20=09=09'-P',=0A=20=09=09= 'null=3D_null_',=0A=20=09=09'-d',=0A-=09=09"$common_connstr=20= user=3Dssltestuser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client_tmp.key",=0A+=09=09"$common_connstr=20= user=3Dssltestuser=20sslcert=3Dclient.crt__client.key=20= sslkey=3Dssl/client_tmp.key",=0A=20=09=09'-c',=0A=20=09=09"SELECT=20*=20= FROM=20pg_stat_ssl=20WHERE=20pid=20=3D=20pg_backend_pid()"=0A=20=09],=0A=20= =09= qr{^pid,ssl,version,cipher,bits,compression,client_dn,client_serial,issuer= _dn\r?\n=0A-=09=09=09=09= ^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,/CN=3Dssltestuser,1,\Q/CN=3DTest=20CA=20= for=20PostgreSQL=20SSL=20regression=20test=20client=20certs\E\r?$}mx,=0A= +=09=09=09=09^\d+,t,TLSv[\d.]+,[\w-]+,\d+,f,CN=3Dssltestuser,1,\QCN=3DTest= =20CA=20for=20PostgreSQL=20SSL=20regression=20test=20client=20= certs\E\r?$}mx,=0A=20=09'pg_stat_ssl=20with=20client=20certificate');=0A=20= =0A=20#=20client=20key=20with=20wrong=20permissions=0A=20SKIP:=0A=20{=0A=20= =09skip=20"Permissions=20check=20not=20enforced=20on=20Windows",=202=20= if=20($windows_os);=0A+=09skip=20"Key=20not=20on=20filesystem=20with=20= NSS",=202=20if=20($nss);=0A=20=0A=20=09test_connect_fails(=0A=20=09=09= $common_connstr,=0A@@=20-494,15=20+488,18=20@@=20SKIP:=0A=20#=20client=20= cert=20belonging=20to=20another=20user=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A-=09"user=3Danotheruser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client_tmp.key",=0A-=09qr/certificate=20authentication=20= failed=20for=20user=20"anotheruser"/,=0A+=09"user=3Danotheruser=20= sslcert=3Dclient.crt__client.key=20sslkey=3Dssl/client_tmp.key",=0A+=09= qr/unable=20to=20verify=20certificate|certificate=20authentication=20= failed=20for=20user=20"anotheruser"/,=0A=20=09"certificate=20= authorization=20fails=20with=20client=20cert=20belonging=20to=20another=20= user"=0A=20);=0A=20=0A+$common_connstr=20=3D=0A+=20=20= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dcertdb=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/client-revoked.crt__client-revoked.key.db";=0A+=0A= =20#=20revoked=20client=20cert=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A-=09"user=3Dssltestuser=20= sslcert=3Dssl/client-revoked.crt=20sslkey=3Dssl/client-revoked_tmp.key",=0A= +=09"user=3Dssltestuser=20sslcert=3Dclient-revoked.crt__client-revoked.key= =20sslkey=3Dssl/client-revoked_tmp.key",=0A=20=09qr/SSL=20error/,=0A=20=09= "certificate=20authorization=20fails=20with=20revoked=20client=20cert");=0A= =20=0A@@=20-510,17=20+507,17=20@@=20test_connect_fails(=0A=20#=20works,=20= iff=20username=20matches=20Common=20Name=0A=20#=20fails,=20iff=20= username=20doesn't=20match=20Common=20Name.=0A=20$common_connstr=20=3D=0A= -=20=20"sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dverifydb=20hostaddr=3D$SERVERHOSTADDR";=0A+=20=20= "sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= dbname=3Dverifydb=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/client.crt__client.key.db";=0A=20=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A-=09"user=3Dssltestuser=20= sslcert=3Dssl/client.crt=20sslkey=3Dssl/client_tmp.key",=0A+=09= "user=3Dssltestuser=20sslcert=3Dclient.crt__client.key=20= sslkey=3Dssl/client_tmp.key",=0A=20=09"auth_option=20= clientcert=3Dverify-full=20succeeds=20with=20matching=20username=20and=20= Common=20Name"=0A=20);=0A=20=0A=20test_connect_fails(=0A=20=09= $common_connstr,=0A-=09"user=3Danotheruser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client_tmp.key",=0A+=09"user=3Danotheruser=20= sslcert=3Dclient.crt__client.key=20sslkey=3Dssl/client_tmp.key",=0A=20=09= qr/FATAL/,=0A=20=09"auth_option=20clientcert=3Dverify-full=20fails=20= with=20mismatching=20username=20and=20Common=20Name"=0A=20);=0A@@=20= -529,24=20+526,22=20@@=20test_connect_fails(=0A=20#=20works,=20when=20= username=20doesn't=20match=20Common=20Name=0A=20test_connect_ok(=0A=20=09= $common_connstr,=0A-=09"user=3Dyetanotheruser=20sslcert=3Dssl/client.crt=20= sslkey=3Dssl/client_tmp.key",=0A+=09"user=3Dyetanotheruser=20= sslcert=3Dclient.crt__client.key=20sslkey=3Dssl/client_tmp.key",=0A=20=09= "auth_option=20clientcert=3Dverify-ca=20succeeds=20with=20mismatching=20= username=20and=20Common=20Name"=0A=20);=0A=20=0A=20#=20intermediate=20= client_ca.crt=20is=20provided=20by=20client,=20and=20isn't=20in=20= server's=20ssl_ca_file=0A=20switch_server_cert($node,=20= 'server-cn-only',=20'root_ca');=0A=20$common_connstr=20=3D=0A-=20=20= "user=3Dssltestuser=20dbname=3Dcertdb=20sslkey=3Dssl/client_tmp.key=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR";=0A+=20= =20"user=3Dssltestuser=20dbname=3Dcertdb=20sslkey=3Dssl/client_tmp.key=20= sslrootcert=3Dssl/root+server_ca.crt=20hostaddr=3D$SERVERHOSTADDR=20= cert_database=3Dssl/nss/client+client_ca.crt__client.key.db";=0A=20=0A=20= test_connect_ok(=0A=20=09$common_connstr,=0A-=09"sslmode=3Drequire=20= sslcert=3Dssl/client+client_ca.crt",=0A+=09"sslmode=3Drequire=20= sslcert=3Dclient+client_ca.crt__client.key",=0A=20=09"intermediate=20= client=20certificate=20is=20provided=20by=20client");=0A= -test_connect_fails($common_connstr,=20"sslmode=3Drequire=20= sslcert=3Dssl/client.crt",=0A-=09qr/SSL=20error/,=20"intermediate=20= client=20certificate=20is=20missing");=0A= +test_connect_fails($common_connstr,=20"sslmode=3Drequire=20= sslcert=3Dclient.crt__client.key",=0A+=09qr/connection=20requires=20a=20= valid=20client=20certificate|SSL=20error/,=20"intermediate=20client=20= certificate=20is=20missing");=0A=20=0A=20#=20clean=20up=0A-foreach=20my=20= $key=20(@keys)=0A-{=0A-=09unlink("ssl/${key}_tmp.key");=0A-}=0A+=0A= +SSL::Server::cleanup();=0Adiff=20--git=20a/src/test/ssl/t/002_scram.pl=20= b/src/test/ssl/t/002_scram.pl=0Aindex=20a1ab911988..d83bc8658b=20100644=0A= ---=20a/src/test/ssl/t/002_scram.pl=0A+++=20= b/src/test/ssl/t/002_scram.pl=0A@@=20-11,11=20+11,11=20@@=20use=20= File::Copy;=0A=20use=20FindBin;=0A=20use=20lib=20$FindBin::RealBin;=0A=20= =0A-use=20SSLServer;=0A+use=20SSL::Server;=0A=20=0A=20if=20= ($ENV{with_openssl}=20ne=20'yes')=0A=20{=0A-=09plan=20skip_all=20=3D>=20= 'SSL=20not=20supported=20by=20this=20build';=0A+=09plan=20skip_all=20=3D>=20= 'OpenSSL=20not=20supported=20by=20this=20build';=0A=20}=0A=20=0A=20#=20= This=20is=20the=20hostname=20used=20to=20connect=20to=20the=20server.=0A= diff=20--git=20a/src/test/ssl/t/SSL/Backend/NSS.pm=20= b/src/test/ssl/t/SSL/Backend/NSS.pm=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..2b44831739=0A---=20/dev/null=0A+++=20= b/src/test/ssl/t/SSL/Backend/NSS.pm=0A@@=20-0,0=20+1,65=20@@=0A+package=20= SSL::Backend::NSS;=0A+=0A+use=20strict;=0A+use=20warnings;=0A+use=20= Exporter;=0A+=0A+our=20@ISA=20=3D=20qw(Exporter);=0A+our=20@EXPORT_OK=20= =3D=20qw(get_new_nss_backend);=0A+=0A+sub=20new=0A+{=0A+=09my=20($class)=20= =3D=20@_;=0A+=0A+=09my=20$self=20=3D=20{=0A+=09=09_library=20=3D>=20= 'NSS'=0A+=09};=0A+=0A+=09bless=20$self,=20$class;=0A+=0A+=09return=20= $self;=0A+}=0A+=0A+sub=20get_new_nss_backend=0A+{=0A+=09my=20$class=20=3D=20= 'SSL::Backend::NSS';=0A+=0A+=09return=20$class->new();=0A+}=0A+=0A+sub=20= init=0A+{=0A+=09#=20Make=20sure=20the=20certificate=20databases=20are=20= in=20place?=0A+}=0A+=0A+sub=20get_library=0A+{=0A+=09my=20($self)=20=3D=20= @_;=0A+=0A+=09return=20$self->{_library};=0A+}=0A+=0A+sub=20= set_server_cert=0A+{=0A+=09my=20$self=20=20=20=20=20=3D=20$_[0];=0A+=09= my=20$certfile=20=3D=20$_[1];=0A+=09my=20$cafile=20=20=20=3D=20$_[2];=0A= +=09my=20$keyfile=20=20=3D=20$_[3];=0A+=0A+=09my=20$cert_nickname=20=3D=20= $certfile=20.=20'.crt__'=20.=20$keyfile=20.=20'.key';=0A+=09my=20= $cert_database=20=3D=20$cert_nickname=20.=20'.db';=0A+=0A+=09my=20= $sslconf=20=3D=20"ssl_ca_file=3D'$cafile.crt'\n"=20.=0A+=09=09= "ssl_cert_file=3D'$cert_nickname'\n"=20.=0A+=09=09"ssl_crl_file=3D''\n"=20= .=0A+=09=09"ssl_database=3D'nss/$cert_database'\n";=0A+=0A+=09return=20= $sslconf;=0A+}=0A+=0A+sub=20cleanup=0A+{=0A+=09#=20Something?=0A+}=0A+=0A= +1;=0Adiff=20--git=20a/src/test/ssl/t/SSL/Backend/OpenSSL.pm=20= b/src/test/ssl/t/SSL/Backend/OpenSSL.pm=0Anew=20file=20mode=20100644=0A= index=200000000000..3d53289196=0A---=20/dev/null=0A+++=20= b/src/test/ssl/t/SSL/Backend/OpenSSL.pm=0A@@=20-0,0=20+1,102=20@@=0A= +package=20SSL::Backend::OpenSSL;=0A+=0A+use=20strict;=0A+use=20= warnings;=0A+use=20Exporter;=0A+=0A+our=20@ISA=20=3D=20qw(Exporter);=0A= +our=20@EXPORT_OK=20=3D=20qw(get_new_openssl_backend);=0A+=0A+our=20= (@keys);=0A+=0A+INIT=0A+{=0A+=09@keys=20=3D=20(=0A+=09=09"client",=20=20=20= =20=20"client-revoked",=0A+=09=09"client-der",=20"client-encrypted-pem",=0A= +=09=09"client-encrypted-der");=0A+}=0A+=0A+sub=20new=0A+{=0A+=09my=20= ($class)=20=3D=20@_;=0A+=0A+=09my=20$self=20=3D=20{=0A+=09=09_library=20= =3D>=20'OpenSSL'=0A+=09};=0A+=0A+=09bless=20$self,=20$class;=0A+=0A+=09= return=20$self;=0A+}=0A+=0A+sub=20get_new_openssl_backend=0A+{=0A+=09my=20= $class=20=3D=20'SSL::Backend::OpenSSL';=0A+=0A+=09my=20$backend=20=3D=20= $class->new();=0A+=0A+=09return=20$backend;=0A+}=0A+=0A+sub=20init=0A+{=0A= +=09#=20The=20client's=20private=20key=20must=20not=20be=20= world-readable,=20so=20take=20a=20copy=0A+=09#=20of=20the=20key=20stored=20= in=20the=20code=20tree=20and=20update=20its=20permissions.=0A+=09#=0A+=09= #=20This=20changes=20ssl/client.key=20to=20ssl/client_tmp.key=20etc=20= for=20the=20rest=0A+=09#=20of=20the=20tests.=0A+=09foreach=20my=20$key=20= (@keys)=0A+=09{=0A+=09=09copy("ssl/${key}.key",=20"ssl/${key}_tmp.key")=0A= +=09=09=20=20or=20die=0A+=09=09=20=20"couldn't=20copy=20ssl/${key}.key=20= to=20ssl/${key}_tmp.key=20for=20permissions=20change:=20$!";=0A+=09=09= chmod=200600,=20"ssl/${key}_tmp.key"=0A+=09=09=20=20or=20die=20"failed=20= to=20change=20permissions=20on=20ssl/${key}_tmp.key:=20$!";=0A+=09}=0A+=0A= +=09#=20Also=20make=20a=20copy=20of=20that=20explicitly=20= world-readable.=20=20We=20can't=0A+=09#=20necessarily=20rely=20on=20the=20= file=20in=20the=20source=20tree=20having=20those=0A+=09#=20permissions.=20= Add=20it=20to=20@keys=20to=20include=20it=20in=20the=20final=20clean=0A+=09= #=20up=20phase.=0A+=09copy("ssl/client.key",=20= "ssl/client_wrongperms_tmp.key")=0A+=09=20=20or=20die=0A+=09=20=20= "couldn't=20copy=20ssl/client.key=20to=20ssl/client_wrongperms_tmp.key:=20= $!";=0A+=09chmod=200644,=20"ssl/client_wrongperms_tmp.key"=0A+=09=20=20= or=20die=20"failed=20to=20change=20permissions=20on=20= ssl/client_wrongperms_tmp.key:=20$!";=0A+=09push=20@keys,=20= 'client_wrongperms';=0A+}=0A+=0A+#=20Change=20the=20configuration=20to=20= use=20given=20server=20cert=20file,=20and=20reload=0A+#=20the=20server=20= so=20that=20the=20configuration=20takes=20effect.=0A+sub=20= set_server_cert=0A+{=0A+=09my=20$self=20=20=20=20=20=3D=20$_[0];=0A+=09= my=20$certfile=20=3D=20$_[1];=0A+=09my=20$cafile=20=20=20=3D=20$_[2]=20= ||=20"root+client_ca";=0A+=09my=20$keyfile=20=20=3D=20$_[3]=20||=20= $certfile;=0A+=0A+=09my=20$sslconf=20=3D=20"ssl_ca_file=3D'$cafile.crt'\n"= =20.=0A+=09=09"ssl_cert_file=3D'$certfile.crt'\n"=20.=0A+=09=09= "ssl_key_file=3D'$keyfile.key'\n"=20.=0A+=09=09= "ssl_crl_file=3D'root+client.crl'\n";=0A+=0A+=09return=20$sslconf;=0A+}=0A= +=0A+sub=20get_library=0A+{=0A+=09my=20($self)=20=3D=20@_;=0A+=0A+=09= return=20$self->{_library};=0A+}=0A+=0A+sub=20cleanup=0A+{=0A+=09foreach=20= my=20$key=20(@keys)=0A+=09{=0A+=09=09unlink("ssl/${key}_tmp.key");=0A+=09= }=0A+}=0A+=0A+1;=0Adiff=20--git=20a/src/test/ssl/t/SSLServer.pm=20= b/src/test/ssl/t/SSL/Server.pm=0Asimilarity=20index=2082%=0Arename=20= from=20src/test/ssl/t/SSLServer.pm=0Arename=20to=20= src/test/ssl/t/SSL/Server.pm=0Aindex=201e392b8fbf..8e970833b5=20100644=0A= ---=20a/src/test/ssl/t/SSLServer.pm=0A+++=20= b/src/test/ssl/t/SSL/Server.pm=0A@@=20-24,15=20+24,34=20@@=0A=20#=20= explicitly=20because=20an=20invalid=20sslcert=20or=20sslrootcert,=20= respectively,=0A=20#=20causes=20those=20to=20be=20ignored.)=0A=20=0A= -package=20SSLServer;=0A+package=20SSL::Server;=0A=20=0A=20use=20strict;=0A= =20use=20warnings;=0A=20use=20PostgresNode;=0A+use=20RecursiveCopy;=0A=20= use=20TestLib;=0A=20use=20File::Basename;=0A=20use=20File::Copy;=0A=20= use=20Test::More;=0A+use=20SSL::Backend::OpenSSL=20= qw(get_new_openssl_backend);=0A+use=20SSL::Backend::NSS=20= qw(get_new_nss_backend);=0A+=0A+our=20($openssl,=20$nss,=20$backend);=0A= +=0A+#=20The=20TLS=20backend=20which=20the=20server=20is=20using=20= should=20be=20mostly=20transparent=20for=0A+#=20the=20user,=20apart=20= from=20individual=20configuration=20settings,=20so=20keep=20the=20= backend=0A+#=20specific=20things=20abstracted=20behind=20SSL::Server.=0A= +if=20($ENV{with_openssl}=20eq=20'yes')=0A+{=0A+=09$backend=20=3D=20= get_new_openssl_backend();=0A+=09$openssl=20=3D=201;=0A+}=0A+elsif=20= ($ENV{with_nss}=20eq=20'yes')=0A+{=0A+=09$backend=20=3D=20= get_new_nss_backend();=0A+=09$nss=20=3D=201;=0A+}=0A=20=0A=20use=20= Exporter=20'import';=0A=20our=20@EXPORT=20=3D=20qw(=0A@@=20-145,12=20= +164,19=20@@=20sub=20configure_test_server_for_ssl=0A=20=09close=20= $sslconf;=0A=20=0A=20=09#=20Copy=20all=20server=20certificates=20and=20= keys,=20and=20client=20root=20cert,=20to=20the=20data=20dir=0A-=09= copy_files("ssl/server-*.crt",=20$pgdata);=0A-=09= copy_files("ssl/server-*.key",=20$pgdata);=0A-=09chmod(0600,=20glob=20= "$pgdata/server-*.key")=20or=20die=20$!;=0A-=09= copy_files("ssl/root+client_ca.crt",=20$pgdata);=0A-=09= copy_files("ssl/root_ca.crt",=20=20=20=20=20=20=20=20$pgdata);=0A-=09= copy_files("ssl/root+client.crl",=20=20=20=20$pgdata);=0A+=09if=20= (defined($openssl))=0A+=09{=0A+=09=09copy_files("ssl/server-*.crt",=20= $pgdata);=0A+=09=09copy_files("ssl/server-*.key",=20$pgdata);=0A+=09=09= chmod(0600,=20glob=20"$pgdata/server-*.key")=20or=20die=20$!;=0A+=09=09= copy_files("ssl/root+client_ca.crt",=20$pgdata);=0A+=09=09= copy_files("ssl/root_ca.crt",=20=20=20=20=20=20=20=20$pgdata);=0A+=09=09= copy_files("ssl/root+client.crl",=20=20=20=20$pgdata);=0A+=09}=0A+=09= elsif=20(defined($nss))=0A+=09{=0A+=09=09= RecursiveCopy::copypath("ssl/nss",=20$pgdata=20.=20"/nss")=20if=20-e=20= "ssl/nss";=0A+=09}=0A=20=0A=20=09#=20Stop=20and=20restart=20server=20to=20= load=20new=20listen_addresses.=0A=20=09$node->restart;=0A@@=20-161,6=20= +187,16=20@@=20sub=20configure_test_server_for_ssl=0A=20=09return;=0A=20= }=0A=20=0A+sub=20ssl_library=0A+{=0A+=09return=20= $backend->get_library();=0A+}=0A+=0A+sub=20cleanup=0A+{=0A+=09= $backend->cleanup();=0A+}=0A+=0A=20#=20Change=20the=20configuration=20to=20= use=20given=20server=20cert=20file,=20and=20reload=0A=20#=20the=20server=20= so=20that=20the=20configuration=20takes=20effect.=0A=20sub=20= switch_server_cert=0A@@=20-168,14=20+204,16=20@@=20sub=20= switch_server_cert=0A=20=09my=20$node=20=20=20=20=20=3D=20$_[0];=0A=20=09= my=20$certfile=20=3D=20$_[1];=0A=20=09my=20$cafile=20=20=20=3D=20$_[2]=20= ||=20"root+client_ca";=0A+=09my=20$keyfile=20=20=3D=20$_[3]=20||=20'';=0A= +=09my=20$pwcmd=20=20=20=20=3D=20$_[4]=20||=20'';=0A=20=09my=20$pgdata=20= =20=20=3D=20$node->data_dir;=0A=20=0A+=09$keyfile=20=3D=20$certfile=20if=20= $keyfile=20eq=20'';=0A+=0A=20=09open=20my=20$sslconf,=20'>',=20= "$pgdata/sslconfig.conf";=0A=20=09print=20$sslconf=20"ssl=3Don\n";=0A-=09= print=20$sslconf=20"ssl_ca_file=3D'$cafile.crt'\n";=0A-=09print=20= $sslconf=20"ssl_cert_file=3D'$certfile.crt'\n";=0A-=09print=20$sslconf=20= "ssl_key_file=3D'$certfile.key'\n";=0A-=09print=20$sslconf=20= "ssl_crl_file=3D'root+client.crl'\n";=0A+=09print=20$sslconf=20= $backend->set_server_cert($certfile,=20$cafile,=20$keyfile);=0A+=09print=20= $sslconf=20"ssl_passphrase_command=3D'$pwcmd'\n";=0A=20=09close=20= $sslconf;=0A=20=0A=20=09$node->restart;=0A--=20=0A2.21.1=20(Apple=20= Git-122.3)=0A=0A= --Apple-Mail=_DD4256D0-7992-400E-A089-6CE7D4CD6E3E--