</listitem>
</varlistentry>
+ <varlistentry id="guc-ssl-min-protocol-version" xreflabel="ssl_min_protocol_version">
+ <term><varname>ssl_min_protocol_version</varname> (<type>enum</type>)
+ <indexterm>
+ <primary><varname>ssl_min_protocol_version</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Sets the minimum SSL/TLS protocol version to use. Valid values are
+ currently: <literal>TLSv1</literal>, <literal>TLSv1.1</literal>,
+ <literal>TLSv1.2</literal>, <literal>TLSv1.3</literal>. Older
+ versions of the <productname>OpenSSL</productname> library do not
+ support all values; an error will be raised if an unsupported setting
+ is chosen. Protocol versions before TLS 1.0, namely SSL version 2 and
+ 3, are always disabled.
+ </para>
+
+ <para>
+ The default is <literal>TLSv1</literal>, mainly to support older
+ versions of the <productname>OpenSSL</productname> library. You might
+ want to set this to a higher value if all software components can
+ support the newer protocol versions.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-max-protocol-version" xreflabel="ssl_max_protocol_version">
+ <term><varname>ssl_max_protocol_version</varname> (<type>enum</type>)
+ <indexterm>
+ <primary><varname>ssl_max_protocol_version</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Sets the maximum SSL/TLS protocol version to use. Valid values are as
+ for <xref linkend="guc-ssl-min-protocol-version"/>, with addition of
+ an empty string, which allows any protocol version. The default is to
+ allow any version. Setting the maximum protocol version is mainly
+ useful for testing or if some component has issues working with a
+ newer protocol.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
<term><varname>ssl_dh_params_file</varname> (<type>string</type>)
<indexterm>
static bool dummy_ssl_passwd_cb_called = false;
static bool ssl_is_server_start;
+static int ssl_protocol_version_to_openssl(int v, const char *guc_name);
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+static int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
+static int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
+#endif
+
/* ------------------------------------------------------------ */
/* Public interface */
goto error;
}
- /* disallow SSL v2/v3 */
- SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ if (ssl_min_protocol_version)
+ SSL_CTX_set_min_proto_version(context,
+ ssl_protocol_version_to_openssl(ssl_min_protocol_version,
+ "ssl_min_protocol_version"));
+ if (ssl_max_protocol_version)
+ SSL_CTX_set_max_proto_version(context,
+ ssl_protocol_version_to_openssl(ssl_max_protocol_version,
+ "ssl_max_protocol_version"));
/* disallow SSL session tickets */
#ifdef SSL_OP_NO_TICKET /* added in OpenSSL 0.9.8f */
return result;
}
+
+/*
+ * Convert TLS protocol version GUC enum to OpenSSL values
+ *
+ * This is a straightforward one-to-one mapping, but doing it this way makes
+ * guc.c independent of OpenSSL availability and version.
+ *
+ * If a version is passed that is not supported by the current OpenSSL
+ * version, then we throw an error, so that subsequent code can assume it's
+ * working with a supported version.
+ */
+static int
+ssl_protocol_version_to_openssl(int v, const char *guc_name)
+{
+ switch (v)
+ {
+ case PG_TLS_ANY:
+ return 0;
+ case PG_TLS1_VERSION:
+ return TLS1_VERSION;
+ case PG_TLS1_1_VERSION:
+#ifdef TLS1_1_VERSION
+ return TLS1_1_VERSION;
+#else
+ goto error;
+#endif
+ case PG_TLS1_2_VERSION:
+#ifdef TLS1_2_VERSION
+ return TLS1_2_VERSION;
+#else
+ goto error;
+#endif
+ case PG_TLS1_3_VERSION:
+#ifdef TLS1_3_VERSION
+ return TLS1_3_VERSION;
+#else
+ goto error;
+#endif
+ }
+
+error:
+ pg_attribute_unused();
+ ereport(ERROR,
+ (errmsg("%s setting %s not supported by this build",
+ guc_name,
+ GetConfigOption(guc_name, false, false))));
+ return -1;
+}
+
+/*
+ * Replacements for APIs present in newer versions of OpenSSL
+ */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+
+/*
+ * OpenSSL versions that support TLS 1.3 shouldn't get here because they
+ * already have these functions. So we don't have to keep updating the below
+ * code for every new TLS version, and eventually it can go away. But let's
+ * just check this to make sure ...
+ */
+#ifdef TLS1_3_VERSION
+#error OpenSSL version mismatch
+#endif
+
+static int
+SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version)
+{
+ int ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+
+ if (version > TLS1_VERSION)
+ ssl_options |= SSL_OP_NO_TLSv1;
+#ifdef TLS1_1_VERSION
+ if (version > TLS1_1_VERSION)
+ ssl_options |= SSL_OP_NO_TLSv1_1;
+#endif
+#ifdef TLS1_2_VERSION
+ if (version > TLS1_2_VERSION)
+ ssl_options |= SSL_OP_NO_TLSv1_2;
+#endif
+
+ SSL_CTX_set_options(ctx, ssl_options);
+
+ return 1; /* success */
+}
+
+static int
+SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version)
+{
+ int ssl_options = 0;
+
+ AssertArg(version != 0);
+
+#ifdef TLS1_1_VERSION
+ if (version < TLS1_1_VERSION)
+ ssl_options |= SSL_OP_NO_TLSv1_1;
+#endif
+#ifdef TLS1_2_VERSION
+ if (version < TLS1_2_VERSION)
+ ssl_options |= SSL_OP_NO_TLSv1_2;
+#endif
+
+ SSL_CTX_set_options(ctx, ssl_options);
+
+ return 1; /* success */
+}
+
+#endif /* OPENSSL_VERSION_NUMBER */
/* GUC variable: if false, prefer client ciphers */
bool SSLPreferServerCiphers;
+int ssl_min_protocol_version;
+int ssl_max_protocol_version;
+
/* ------------------------------------------------------------ */
/* Procedures common to all secure sessions */
/* ------------------------------------------------------------ */
{NULL, 0, false}
};
+const struct config_enum_entry ssl_protocol_versions_info[] = {
+ {"", PG_TLS_ANY, false},
+ {"TLSv1", PG_TLS1_VERSION, false},
+ {"TLSv1.1", PG_TLS1_1_VERSION, false},
+ {"TLSv1.2", PG_TLS1_2_VERSION, false},
+ {"TLSv1.3", PG_TLS1_3_VERSION, false},
+ {NULL, 0, false}
+};
+
/*
* Options for enum values stored in other modules
*/
NULL, NULL, NULL
},
+ {
+ {"ssl_min_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
+ gettext_noop("Sets the minimum SSL/TLS protocol version to use."),
+ NULL,
+ GUC_SUPERUSER_ONLY
+ },
+ &ssl_min_protocol_version,
+ PG_TLS1_VERSION,
+ ssl_protocol_versions_info + 1 /* don't allow PG_TLS_ANY */,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_max_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
+ gettext_noop("Sets the maximum SSL/TLS protocol version to use."),
+ NULL,
+ GUC_SUPERUSER_ONLY
+ },
+ &ssl_max_protocol_version,
+ PG_TLS_ANY,
+ ssl_protocol_versions_info,
+ NULL, NULL, NULL
+ },
+
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
+#ssl_min_protocol_version = 'TLSv1'
+#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off
extern char *SSLCipherSuites;
extern char *SSLECDHCurve;
extern bool SSLPreferServerCiphers;
+extern int ssl_min_protocol_version;
+extern int ssl_max_protocol_version;
+
+enum ssl_protocol_versions
+{
+ PG_TLS_ANY = 0,
+ PG_TLS1_VERSION,
+ PG_TLS1_1_VERSION,
+ PG_TLS1_2_VERSION,
+ PG_TLS1_3_VERSION,
+};
/*
* prototypes for functions in be-secure-common.c