@@ -67,6 +67,12 @@ static int ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdat
6767static int dummy_ssl_passwd_cb (char * buf , int size , int rwflag , void * userdata );
6868static int verify_cb (int ok , X509_STORE_CTX * ctx );
6969static void info_cb (const SSL * ssl , int type , int args );
70+ static int alpn_cb (SSL * ssl ,
71+ const unsigned char * * out ,
72+ unsigned char * outlen ,
73+ const unsigned char * in ,
74+ unsigned int inlen ,
75+ void * userdata );
7076static bool initialize_dh (SSL_CTX * context , bool isServerStart );
7177static bool initialize_ecdh (SSL_CTX * context , bool isServerStart );
7278static const char * SSLerrmessage (unsigned long ecode );
@@ -432,6 +438,9 @@ be_tls_open_server(Port *port)
432438 /* set up debugging/info callback */
433439 SSL_CTX_set_info_callback (SSL_context , info_cb );
434440
441+ /* enable ALPN */
442+ SSL_CTX_set_alpn_select_cb (SSL_context , alpn_cb , port );
443+
435444 if (!(port -> ssl = SSL_new (SSL_context )))
436445 {
437446 ereport (COMMERROR ,
@@ -571,6 +580,32 @@ be_tls_open_server(Port *port)
571580 return -1 ;
572581 }
573582
583+ /* Get the protocol selected by ALPN */
584+ port -> alpn_used = false;
585+ {
586+ const unsigned char * selected ;
587+ unsigned int len ;
588+
589+ SSL_get0_alpn_selected (port -> ssl , & selected , & len );
590+
591+ /* If ALPN is used, check that we negotiated the expected protocol */
592+ if (selected != NULL )
593+ {
594+ if (len == strlen (PG_ALPN_PROTOCOL ) &&
595+ memcmp (selected , PG_ALPN_PROTOCOL , strlen (PG_ALPN_PROTOCOL )) == 0 )
596+ {
597+ port -> alpn_used = true;
598+ }
599+ else
600+ {
601+ /* shouldn't happen */
602+ ereport (COMMERROR ,
603+ (errcode (ERRCODE_PROTOCOL_VIOLATION ),
604+ errmsg ("received SSL connection request with unexpected ALPN protocol" )));
605+ }
606+ }
607+ }
608+
574609 /* Get client certificate, if available. */
575610 port -> peer = SSL_get_peer_certificate (port -> ssl );
576611
@@ -1259,6 +1294,48 @@ info_cb(const SSL *ssl, int type, int args)
12591294 }
12601295}
12611296
1297+ /* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */
1298+ static const unsigned char alpn_protos [] = PG_ALPN_PROTOCOL_VECTOR ;
1299+
1300+ /*
1301+ * Server callback for ALPN negotiation. We use the standard "helper" function
1302+ * even though currently we only accept one value.
1303+ */
1304+ static int
1305+ alpn_cb (SSL * ssl ,
1306+ const unsigned char * * out ,
1307+ unsigned char * outlen ,
1308+ const unsigned char * in ,
1309+ unsigned int inlen ,
1310+ void * userdata )
1311+ {
1312+ /*
1313+ * Why does OpenSSL provide a helper function that requires a nonconst
1314+ * vector when the callback is declared to take a const vector? What are
1315+ * we to do with that?
1316+ */
1317+ int retval ;
1318+
1319+ Assert (userdata != NULL );
1320+ Assert (out != NULL );
1321+ Assert (outlen != NULL );
1322+ Assert (in != NULL );
1323+
1324+ retval = SSL_select_next_proto ((unsigned char * * ) out , outlen ,
1325+ alpn_protos , sizeof (alpn_protos ),
1326+ in , inlen );
1327+ if (* out == NULL || * outlen > sizeof (alpn_protos ) || outlen <= 0 )
1328+ return SSL_TLSEXT_ERR_NOACK ; /* can't happen */
1329+
1330+ if (retval == OPENSSL_NPN_NEGOTIATED )
1331+ return SSL_TLSEXT_ERR_OK ;
1332+ else if (retval == OPENSSL_NPN_NO_OVERLAP )
1333+ return SSL_TLSEXT_ERR_NOACK ;
1334+ else
1335+ return SSL_TLSEXT_ERR_NOACK ;
1336+ }
1337+
1338+
12621339/*
12631340 * Set DH parameters for generating ephemeral DH keys. The
12641341 * DH parameters can take a long time to compute, so they must be
0 commit comments