diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 60cf68aac4..be41d75de0 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -67,6 +67,7 @@ static int ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdat static int dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata); static int verify_cb(int ok, X509_STORE_CTX *ctx); static void info_cb(const SSL *ssl, int type, int args); +static int client_hello_cb(SSL *ssl, int *al, void *arg); static int alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, @@ -443,6 +444,9 @@ be_tls_open_server(Port *port) /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); + /* enable ClientHello */ + SSL_CTX_set_client_hello_cb(SSL_context, client_hello_cb, NULL); + /* enable ALPN */ SSL_CTX_set_alpn_select_cb(SSL_context, alpn_cb, port); @@ -1304,6 +1308,30 @@ info_cb(const SSL *ssl, int type, int args) /* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */ static const unsigned char alpn_protos[] = PG_ALPN_PROTOCOL_VECTOR; +/* + * Server callback for ClientHello validation. + */ +static int +client_hello_cb(SSL *ssl, + int *al, + void *arg) +{ + const unsigned char * data; + size_t len; + + if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_application_layer_protocol_negotiation, &data, &len) == 1) + return SSL_CLIENT_HELLO_SUCCESS; + else + { + /* + * The client doesn't support ALPN negotiation protocol. Reject the connection + * with TLS "no_application_protocol" alert, per RFC 7301. + */ + *al = TLS1_AD_NO_APPLICATION_PROTOCOL; + return SSL_CLIENT_HELLO_ERROR; + } +} + /* * Server callback for ALPN negotiation. We use the standard "helper" function * even though currently we only accept one value.