diff options
Diffstat (limited to 'src/interfaces/libpq/fe-secure-openssl.c')
-rw-r--r-- | src/interfaces/libpq/fe-secure-openssl.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 0e84fc8ac6f..026b14fa724 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -30,6 +30,7 @@ #include "fe-auth.h" #include "fe-secure-common.h" #include "libpq-int.h" +#include "common/openssl.h" #ifdef WIN32 #include "win32.h" @@ -95,6 +96,7 @@ static long win32_ssl_create_mutex = 0; #endif /* ENABLE_THREAD_SAFETY */ static PQsslKeyPassHook_type PQsslKeyPassHook = NULL; +static int ssl_protocol_version_to_openssl(const char *protocol); /* ------------------------------------------------------------ */ /* Procedures common to all secure sessions */ @@ -843,6 +845,59 @@ initialize_SSL(PGconn *conn) /* Disable old protocol versions */ SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + /* Set the minimum and maximum protocol versions if necessary */ + if (conn->sslminprotocolversion && + strlen(conn->sslminprotocolversion) != 0) + { + int ssl_min_ver; + + ssl_min_ver = ssl_protocol_version_to_openssl(conn->sslminprotocolversion); + + if (ssl_min_ver == -1) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid value \"%s\" for minimum version of SSL protocol\n"), + conn->sslminprotocolversion); + return -1; + } + + if (!SSL_CTX_set_min_proto_version(SSL_context, ssl_min_ver)) + { + char *err = SSLerrmessage(ERR_get_error()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not set minimum version of SSL protocol: %s\n"), + err); + return -1; + } + } + + if (conn->sslmaxprotocolversion && + strlen(conn->sslmaxprotocolversion) != 0) + { + int ssl_max_ver; + + ssl_max_ver = ssl_protocol_version_to_openssl(conn->sslmaxprotocolversion); + + if (ssl_max_ver == -1) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid value \"%s\" for maximum version of SSL protocol\n"), + conn->sslmaxprotocolversion); + return -1; + } + + if (!SSL_CTX_set_max_proto_version(SSL_context, ssl_max_ver)) + { + char *err = SSLerrmessage(ERR_get_error()); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not set maximum version of SSL protocol: %s\n"), + err); + return -1; + } + } + /* * Disable OpenSSL's moving-write-buffer sanity check, because it causes * unnecessary failures in nonblocking send cases. @@ -1659,3 +1714,37 @@ PQssl_passwd_cb(char *buf, int size, int rwflag, void *userdata) else return PQdefaultSSLKeyPassHook(buf, size, conn); } + +/* + * Convert TLS protocol version string to OpenSSL values + * + * If a version is passed that is not supported by the current OpenSSL version, + * then we return -1. If a non-negative value is returned, subsequent code can + * assume it is working with a supported version. + * + * Note: this is rather similar to the backend routine in be-secure-openssl.c, + * so make sure to update both routines if changing this one. + */ +static int +ssl_protocol_version_to_openssl(const char *protocol) +{ + if (pg_strcasecmp("TLSv1", protocol) == 0) + return TLS1_VERSION; + +#ifdef TLS1_1_VERSION + if (pg_strcasecmp("TLSv1.1", protocol) == 0) + return TLS1_1_VERSION; +#endif + +#ifdef TLS1_2_VERSION + if (pg_strcasecmp("TLSv1.2", protocol) == 0) + return TLS1_2_VERSION; +#endif + +#ifdef TLS1_3_VERSION + if (pg_strcasecmp("TLSv1.3", protocol) == 0) + return TLS1_3_VERSION; +#endif + + return -1; +} |