Michael Paquier <michael.paqu...@gmail.com> writes:
>>>
>>> Perhaps ssloptions.[ch], unless you plan to add non-option-related code
>>> there later?
>>
>> I don't think anything else than common options-related code fits in
>> there, so ssloptions.c makes sense to me.
>>
>>> BTW, there is no Regent code in your openssl.c, so the copyright
>>> statement is incorrect.
>>
>> Good catch, I just blindly copied that from some other file.
> There have been arguments in favor and against this patch... But
> marking it as returned with feedback because of a lack of activity in
> the last couple of weeks. Feel free to update if you think that's not
> correct, and please move this patch to commit fest 2014-12.

Attached is a new version that addresses the earlier feedback: renamed
the added *.[ch] files and removed incorrect copyright line.

I'm moving this to the current CF.

--
Alex

>From 18388300f9ed34fa47c66b8a2da098aeb19a7f71 Mon Sep 17 00:00:00 2001
From: Alex Shulgin <a...@commandprompt.com>
Date: Wed, 19 Nov 2014 19:49:29 +0300
Subject: [PATCH] DRAFT: ssl_protocols GUC

---
 doc/src/sgml/config.sgml                      |  29 ++++++
 doc/src/sgml/libpq.sgml                       |  25 ++++++
 src/backend/libpq/Makefile                    |   2 +-
 src/backend/libpq/be-secure-openssl.c         |  29 ++++--
 src/backend/libpq/be-secure.c                 |   3 +-
 src/backend/libpq/ssloptions.c                | 123 ++++++++++++++++++++++++++
 src/backend/utils/misc/guc.c                  |  15 ++++
 src/backend/utils/misc/postgresql.conf.sample |   1 +
 src/include/libpq/libpq.h                     |   1 +
 src/include/libpq/ssloptions.h                |  48 ++++++++++
 src/interfaces/libpq/Makefile                 |   8 +-
 src/interfaces/libpq/fe-connect.c             |   4 +
 src/interfaces/libpq/fe-secure-openssl.c      |  18 +++-
 src/interfaces/libpq/libpq-int.h              |   1 +
 14 files changed, 297 insertions(+), 10 deletions(-)
 create mode 100644 src/backend/libpq/ssloptions.c
 create mode 100644 src/include/libpq/ssloptions.h

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
new file mode 100644
index 48ae3e4..699f0f9
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** include_dir 'conf.d'
*** 1055,1060 ****
--- 1055,1089 ----
        </listitem>
       </varlistentry>
  
+      <varlistentry id="guc-ssl-protocols" xreflabel="ssl_protocols">
+       <term><varname>ssl_protocols</varname> (<type>string</type>)
+       <indexterm>
+        <primary><varname>ssl_protocols</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Specifies a colon-separated list of <acronym>SSL</> protocols that are
+         allowed to be used on secure connections. Each entry in the list can
+         be prefixed by a <literal>+</> (add to the current list)
+         or <literal>-</> (remove from the current list). If no prefix is used,
+         the list is replaced with the specified protocol.
+        </para>
+        <para>
+         The full list of supported protocols can be found in the
+         the <application>openssl</> manual page.  In addition to the names of
+         individual protocols, the following keywords can be
+         used: <literal>ALL</> (all protocols supported by the underlying
+         crypto library), <literal>SSL</> (all supported versions
+         of <acronym>SSL</>) and <literal>TLS</> (all supported versions
+         of <acronym>TLS</>).
+        </para>
+        <para>
+         The default is <literal>ALL:-SSL</literal>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
       <varlistentry id="guc-ssl-ciphers" xreflabel="ssl_ciphers">
        <term><varname>ssl_ciphers</varname> (<type>string</type>)
        <indexterm>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
new file mode 100644
index d829a4b..62ee0b4
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
*************** postgresql://%2Fvar%2Flib%2Fpostgresql/d
*** 1230,1235 ****
--- 1230,1250 ----
        </listitem>
       </varlistentry>
  
+      <varlistentry id="libpq-connect-sslprotocols" xreflabel="sslprotocols">
+       <term><literal>sslprotocols</literal></term>
+       <listitem>
+        <para>
+         Specifies a colon-separated list of <acronym>SSL</> protocols that are
+         allowed to be used on secure connections.
+         See <xref linkend="guc-ssl-protocols"> server configuration parameter
+         for format.
+        </para>
+        <para>
+         Defaults to <literal>ALL:-SSL</>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
       <varlistentry id="libpq-connect-sslcompression" xreflabel="sslcompression">
        <term><literal>sslcompression</literal></term>
        <listitem>
*************** myEventProc(PGEventId evtId, void *evtIn
*** 6693,6698 ****
--- 6708,6723 ----
       </para>
      </listitem>
  
+     <listitem>
+      <para>
+       <indexterm>
+        <primary><envar>PGSSLPROTOCOLS</envar></primary>
+       </indexterm>
+       <envar>PGSSLPROTOCOLS</envar> behaves the same as the <xref
+       linkend="libpq-connect-sslprotocols"> connection parameter.
+      </para>
+     </listitem>
+ 
      <listitem>
       <para>
        <indexterm>
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
new file mode 100644
index 09410c4..62abd46
*** a/src/backend/libpq/Makefile
--- b/src/backend/libpq/Makefile
*************** OBJS = be-fsstubs.o be-secure.o auth.o c
*** 18,24 ****
         pqformat.o pqmq.o pqsignal.o
  
  ifeq ($(with_openssl),yes)
! OBJS += be-secure-openssl.o
  endif
  
  include $(top_srcdir)/src/backend/common.mk
--- 18,24 ----
         pqformat.o pqmq.o pqsignal.o
  
  ifeq ($(with_openssl),yes)
! OBJS += be-secure-openssl.o ssloptions.o
  endif
  
  include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
new file mode 100644
index b05364c..ad7e0f6
*** a/src/backend/libpq/be-secure-openssl.c
--- b/src/backend/libpq/be-secure-openssl.c
***************
*** 71,76 ****
--- 71,77 ----
  #endif
  
  #include "libpq/libpq.h"
+ #include "libpq/ssloptions.h"
  #include "tcop/tcopprot.h"
  #include "utils/memutils.h"
  
*************** KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n
*** 169,175 ****
  void
  be_tls_init(void)
  {
! 	struct stat buf;
  
  	STACK_OF(X509_NAME) *root_cert_list = NULL;
  
--- 170,178 ----
  void
  be_tls_init(void)
  {
! 	struct stat		buf;
! 	long			protocol_options,
! 					disallow_ssl_options;
  
  	STACK_OF(X509_NAME) *root_cert_list = NULL;
  
*************** be_tls_init(void)
*** 245,259 ****
  							SSLerrmessage())));
  	}
  
! 	/* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
  	SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
! 	SSL_CTX_set_options(SSL_context,
! 						SSL_OP_SINGLE_DH_USE |
! 						SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
  
  	/* set up ephemeral ECDH keys */
  	initialize_ecdh();
  
  	/* set up the allowed cipher list */
  	if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
  		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
--- 248,278 ----
  							SSLerrmessage())));
  	}
  
! 	/* set up ephemeral DH keys */
  	SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
! 	SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE);
  
  	/* set up ephemeral ECDH keys */
  	initialize_ecdh();
  
+ 	/* set up the allowed protocol list */
+ 	if (!options_from_ssl_protocols_string(SSLProtocols, &protocol_options))
+ 		ereport(FATAL,
+ 				(errmsg("invalid SSL protocol list: %s", SSLProtocols),
+ 				 errhint("are you missing 'ALL:' before '-BADPROTO'?")));
+ 
+ 	/* forcibly disallow SSLv2 and SSLv3 */
+ 	disallow_ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ 
+ 	if ((protocol_options & disallow_ssl_options) != disallow_ssl_options)
+ 	{
+ 		elog(WARNING, "removing SSLv2 and SSLv3 from SSL protocol list");
+ 		protocol_options |= disallow_ssl_options;
+ 	}
+ 	elog(DEBUG2, "disabling SSL protocols: %lx", protocol_options);
+ 
+ 	SSL_CTX_set_options(SSL_context, protocol_options);
+ 
  	/* set up the allowed cipher list */
  	if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
  		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
new file mode 100644
index 41ec1ad..a5a5f3f
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
*************** int			ssl_renegotiation_limit;
*** 52,58 ****
  bool ssl_loaded_verify_locations = false;
  #endif
  
! /* GUC variable controlling SSL cipher list */
  char	   *SSLCipherSuites = NULL;
  
  /* GUC variable for default ECHD curve. */
--- 52,59 ----
  bool ssl_loaded_verify_locations = false;
  #endif
  
! /* GUC variables controlling SSL protocol and cipher list */
! char	   *SSLProtocols = NULL;
  char	   *SSLCipherSuites = NULL;
  
  /* GUC variable for default ECHD curve. */
diff --git a/src/backend/libpq/ssloptions.c b/src/backend/libpq/ssloptions.c
new file mode 100644
index ...e161c1e
*** a/src/backend/libpq/ssloptions.c
--- b/src/backend/libpq/ssloptions.c
***************
*** 0 ****
--- 1,123 ----
+ /*-------------------------------------------------------------------------
+  *
+  * ssloptions.c
+  *	  shared functions for setting OpenSSL options.
+  *
+  *
+  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *	  src/backend/libpq/ssloptions.c
+  *
+  *	  Contains functions that both backend and frontend can use to setup
+  *	  options for a secure connection.
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include <openssl/ssl.h>
+ #if SSLEAY_VERSION_NUMBER >= 0x0907000L
+ #include <openssl/conf.h>
+ #endif
+ 
+ #include "libpq/libpq.h"
+ #include "libpq/ssloptions.h"
+ 
+ /*
+  *	Parse the SSL allowed protocol list
+  *
+  *	The logic here is inverted.  OpenSSL does not take a list of
+  *	protocols to use, but a list of protocols to avoid.  We use the
+  *	same bits with the opposite meaning, then invert the result.
+  */
+ 
+ #define SSL_PROTO_SSLv2		SSL_OP_NO_SSLv2
+ #define SSL_PROTO_SSLv3		SSL_OP_NO_SSLv3
+ #define SSL_PROTO_SSL		(SSL_PROTO_SSLv2 | SSL_PROTO_SSLv3)
+ #define SSL_PROTO_TLSv1		SSL_OP_NO_TLSv1
+ #ifdef SSL_OP_NO_TLSv1_1
+ #define SSL_PROTO_TLSv1_1	SSL_OP_NO_TLSv1_1
+ #else
+ #define SSL_PROTO_TLSv1_1	0
+ #endif
+ #ifdef SSL_OP_NO_TLSv1_2
+ #define SSL_PROTO_TLSv1_2	SSL_OP_NO_TLSv1_2
+ #else
+ #define SSL_PROTO_TLSv1_2	0
+ #endif
+ #define SSL_PROTO_TLS		(SSL_PROTO_TLSv1 | SSL_PROTO_TLSv1_1 | SSL_PROTO_TLSv1_2)
+ #define SSL_PROTO_ALL		(SSL_PROTO_SSL | SSL_PROTO_TLS)
+ #define SSL_PROTO_NONE		0
+ 
+ #define str_is_token(str, tok, len) \
+ 	(len == sizeof(tok) - 1 && pg_strncasecmp(str, tok, len) == 0)
+ 
+ 
+ bool
+ options_from_ssl_protocols_string(const char *str, long *options)
+ {
+ 	long result, current;
+ 	const char *p, *q;
+ 	int action;
+ 
+ 	/*
+ 	 * Iterate over the colon-separated list of protocols.  If a protocol is
+ 	 * preceded by a +, it is added to the list.  If it is preceded by a -, it
+ 	 * is removed from the list.  If it is not preceded by anything, the list
+ 	 * is set to exactly that protocol.  "ALL" can be used to indicate all
+ 	 * protocols, "NONE" to indicate no protocols, "SSL" to indicate all SSL
+ 	 * protocols and "TLS" to indicate all TLS protocols.
+ 	 */
+ 	result = SSL_PROTO_NONE;
+ 	for (p = q = str; *q; p = q + 1) {
+ 		for (q = p; *q && *q != ':'; ++q)
+ 			/* nothing */ ;
+ 		if (*p == '-' || *p == '+')
+ 			action = *p++;
+ 		else
+ 			action = '=';
+ 		if (str_is_token(p, "ALL", q - p))
+ 			current = SSL_PROTO_ALL;
+ 		else if (str_is_token(p, "NONE", q - p))
+ 			current = SSL_PROTO_NONE;
+ 		else if (str_is_token(p, SSL_TXT_SSLV2, q - p))
+ 			current = SSL_PROTO_SSLv2;
+ 		else if (str_is_token(p, SSL_TXT_SSLV3, q - p))
+ 			current = SSL_PROTO_SSLv3;
+ 		else if (str_is_token(p, "SSL", q - p))
+ 			current = SSL_PROTO_SSL;
+ 		else if (str_is_token(p, SSL_TXT_TLSV1, q - p))
+ 			current = SSL_PROTO_TLSv1;
+ #ifdef SSL_OP_NO_TLSv1_1
+ 		else if (str_is_token(p, SSL_TXT_TLSV1_1, q - p))
+ 			current = SSL_PROTO_TLSv1_1;
+ #endif
+ #ifdef SSL_OP_NO_TLSv1_2
+ 		else if (str_is_token(p, SSL_TXT_TLSV1_2, q - p))
+ 			current = SSL_PROTO_TLSv1_2;
+ #endif
+ 		else if (str_is_token(p, "TLS", q - p))
+ 			current = SSL_PROTO_TLS;
+ 		else
+ 			return false;
+ 		switch (action) {
+ 		case '+':
+ 			result |= current;
+ 			break;
+ 		case '-':
+ 			result &= ~current;
+ 			break;
+ 		default:
+ 			result = current;
+ 			break;
+ 		}
+ 	}
+ 	if (result == SSL_PROTO_NONE)
+ 		return false;
+ 
+ 	*options = (SSL_PROTO_ALL & ~result);
+ 	return true;
+ }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index b1bff7f..c54c55b
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static struct config_string ConfigureNam
*** 3245,3250 ****
--- 3245,3265 ----
  	},
  
  	{
+ 		{"ssl_protocols", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ 			gettext_noop("Sets the list of allowed SSL protocols."),
+ 			NULL,
+ 			GUC_SUPERUSER_ONLY
+ 		},
+ 		&SSLProtocols,
+ #ifdef USE_SSL
+ 		"ALL:-SSL",
+ #else
+ 		"none",
+ #endif
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"ssl_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY,
  			gettext_noop("Sets the list of allowed SSL ciphers."),
  			NULL,
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index b053659..bb44aa6
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 79,84 ****
--- 79,85 ----
  
  #authentication_timeout = 1min		# 1s-600s
  #ssl = off				# (change requires restart)
+ #ssl_protocols = 'ALL:-SSL'		# allowed SSL protocols
  #ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
  					# (change requires restart)
  #ssl_prefer_server_ciphers = on		# (change requires restart)
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
new file mode 100644
index 2a61a9e..eb8dfee
*** a/src/include/libpq/libpq.h
--- b/src/include/libpq/libpq.h
*************** extern ssize_t secure_raw_write(Port *po
*** 108,113 ****
--- 108,114 ----
  extern bool ssl_loaded_verify_locations;
  
  /* GUCs */
+ extern char *SSLProtocols;
  extern char *SSLCipherSuites;
  extern char *SSLECDHCurve;
  extern bool SSLPreferServerCiphers;
diff --git a/src/include/libpq/ssloptions.h b/src/include/libpq/ssloptions.h
new file mode 100644
index ...92e8561
*** a/src/include/libpq/ssloptions.h
--- b/src/include/libpq/ssloptions.h
***************
*** 0 ****
--- 1,48 ----
+ /*-------------------------------------------------------------------------
+  *
+  * ssloptions.h
+  *	  declarations of shared functions for setting OpenSSL options.
+  *
+  *
+  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+  *
+  * src/include/libpq/ssloptions.h
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef SSLOPTIONS_H
+ #define SSLOPTIONS_H
+ 
+ /*
+  * Parse the list of SSL protocols in the colon-separated format and return a
+  * bitmask of options to be passed to SSL_CTX_set_options().
+  *
+  * Recognized protocol names are SSLv2, SSLv3 and TLSv1.
+  *
+  * In case the OpenSSL version defines SSL_OP_NO_TLSv1_1, the string TLSv1.1
+  * is also recognized (ditto for SSL_OP_NO_TLSv1_2 and TLSv1.2).
+  *
+  * Additionally, SSL means all supported SSL versions, the same goes for TLS.
+  * Furthermore, ALL means all supported protocols (and NONE, well you've
+  * guessed it.)
+  *
+  * A plus sign before the protocol name includes a protocol in the list, minus
+  * removes, otherwise replaces the whole list.
+  *
+  * Example: ALL:-SSL
+  *
+  * The above example includes all supported protocols except all SSL versions
+  * (SSLv2 and SSLv3).
+  *
+  * Since OpenSSL API only let you *exclude* protocols in the options, the
+  * resulting bitmask will have SSL_OP_NO_<protocol> flags set for which there
+  * were protocols listed with a minus sign.
+  *
+  * Returns true on success, false otherwise (i.e. unrecognized protocol
+  * found in the list).
+  *
+  * On success, stores the result of parsing in the options out-parameter.
+  */
+ extern bool options_from_ssl_protocols_string(const char *str, long *options);
+ 
+ #endif /* SSLOPTIONS_H */
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
new file mode 100644
index 18d9b85..31acdc3
*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
*************** OBJS += chklocale.o inet_net_ntop.o nobl
*** 40,51 ****
--- 40,55 ----
  # libpgport C files that are needed if identified by configure
  OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS))
  # backend/libpq
+ backend_c = ip.c md5.c
  OBJS += ip.o md5.o
  # utils/mb
  OBJS += encnames.o wchar.o
  
  ifeq ($(with_openssl),yes)
  OBJS += fe-secure-openssl.o
+ # backend/libpq
+ backend_c += ssloptions.c
+ OBJS += ssloptions.o
  endif
  
  ifeq ($(PORTNAME), cygwin)
*************** backend_src = $(top_srcdir)/src/backend
*** 96,102 ****
  chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
! ip.c md5.c: % : $(backend_src)/libpq/%
  	rm -f $@ && $(LN_S) $< .
  
  encnames.c wchar.c: % : $(backend_src)/utils/mb/%
--- 100,106 ----
  chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
  	rm -f $@ && $(LN_S) $< .
  
! $(backend_c): % : $(backend_src)/libpq/%
  	rm -f $@ && $(LN_S) $< .
  
  encnames.c wchar.c: % : $(backend_src)/utils/mb/%
*************** clean distclean: clean-lib
*** 156,162 ****
  	rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c pqsignal.c thread.c
  	rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c system.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c
  	rm -f pgsleep.c
! 	rm -f md5.c ip.c
  	rm -f encnames.c wchar.c
  
  maintainer-clean: distclean maintainer-clean-lib
--- 160,166 ----
  	rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c pqsignal.c thread.c
  	rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c system.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c
  	rm -f pgsleep.c
! 	rm -f $(backend_c)
  	rm -f encnames.c wchar.c
  
  maintainer-clean: distclean maintainer-clean-lib
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
new file mode 100644
index 3bac2bc..33dc826
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** static const internalPQconninfoOption PQ
*** 254,259 ****
--- 254,263 ----
  		"SSL-Mode", "", 12,		/* sizeof("verify-full") == 12 */
  	offsetof(struct pg_conn, sslmode)},
  
+ 	{"sslprotocols", "PGSSLPROTOCOLS", "ALL:-SSL", NULL,
+ 		"SSL-Protocols", "", 10,
+ 	offsetof(struct pg_conn, sslprotocols)},
+ 
  	{"sslcompression", "PGSSLCOMPRESSION", "1", NULL,
  		"SSL-Compression", "", 1,
  	offsetof(struct pg_conn, sslcompression)},
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
new file mode 100644
index 7fcc1f0..85c405a
*** a/src/interfaces/libpq/fe-secure-openssl.c
--- b/src/interfaces/libpq/fe-secure-openssl.c
***************
*** 29,34 ****
--- 29,35 ----
  #include "libpq-fe.h"
  #include "fe-auth.h"
  #include "libpq-int.h"
+ #include "libpq/ssloptions.h"
  
  #ifdef WIN32
  #include "win32.h"
*************** pgtls_init(PGconn *conn)
*** 815,820 ****
--- 816,823 ----
  
  	if (!SSL_context)
  	{
+ 		long	protocol_options;
+ 
  		if (pq_init_ssl_lib)
  		{
  #if SSLEAY_VERSION_NUMBER >= 0x00907000L
*************** pgtls_init(PGconn *conn)
*** 845,852 ****
  			return -1;
  		}
  
  		/* Disable old protocol versions */
! 		SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
  
  		/*
  		 * Disable OpenSSL's moving-write-buffer sanity check, because it
--- 848,868 ----
  			return -1;
  		}
  
+ 		/* set up the allowed protocol list */
+ 		if (!options_from_ssl_protocols_string(conn->sslprotocols,
+ 											   &protocol_options))
+ 		{
+ 			printfPQExpBuffer(&conn->errorMessage,
+ 							  libpq_gettext("invalid SSL protocols list (are you missing 'ALL:' before '-BADPROTO'?)\n"));
+ #ifdef ENABLE_THREAD_SAFETY
+ 			pthread_mutex_unlock(&ssl_config_mutex);
+ #endif
+ 			return -1;
+ 		}
+ 
  		/* Disable old protocol versions */
! 		protocol_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
! 		SSL_CTX_set_options(SSL_context, protocol_options);
  
  		/*
  		 * Disable OpenSSL's moving-write-buffer sanity check, because it
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
new file mode 100644
index c345571..28015e9
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** struct pg_conn
*** 324,329 ****
--- 324,330 ----
  	char	   *keepalives_count;		/* maximum number of TCP keepalive
  										 * retransmits */
  	char	   *sslmode;		/* SSL mode (require,prefer,allow,disable) */
+ 	char	   *sslprotocols;	/* SSL protocols (e.g, "ALL:-SSL") */
  	char	   *sslcompression; /* SSL compression (0 or 1) */
  	char	   *sslkey;			/* client key filename */
  	char	   *sslcert;		/* client certificate filename */
-- 
2.1.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to