Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit91044ae

Browse files
committed
Send ALPN in TLS handshake, require it in direct SSL connections
libpq now always tries to send ALPN. With the traditional negotiatedSSL connections, the server accepts the ALPN, and refuses theconnection if it's not what we expect, but connecting without ALPN isstill OK. With the new direct SSL connections, ALPN is mandatory.NOTE: This uses "TBD-pgsql" as the protocol ID. We must register aproper one with IANA before the release!Author: Greg Stark, Heikki LinnakangasReviewed-by: Matthias van de Meent, Jacob Champion
1 parentd39a49c commit91044ae

File tree

7 files changed

+157
-2
lines changed

7 files changed

+157
-2
lines changed

‎doc/src/sgml/libpq.sgml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,6 +2944,18 @@ const char *PQsslAttribute(const PGconn *conn, const char *attribute_name);
29442944
</para>
29452945
</listitem>
29462946
</varlistentry>
2947+
<varlistentry>
2948+
<term><literal>alpn</literal></term>
2949+
<listitem>
2950+
<para>
2951+
Application protocol selected by the TLS Application-Layer
2952+
Protocol Negotiation (ALPN) extension. The only protocol
2953+
supported by libpq is <literal>TBD-pgsql</literal>, so this is
2954+
mainly useful for checking whether the server supported ALPN or
2955+
not. Empty string if ALPN was not used.
2956+
</para>
2957+
</listitem>
2958+
</varlistentry>
29472959
</variablelist>
29482960
</para>
29492961

‎src/backend/libpq/be-secure-openssl.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ static intssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdat
6767
staticintdummy_ssl_passwd_cb(char*buf,intsize,intrwflag,void*userdata);
6868
staticintverify_cb(intok,X509_STORE_CTX*ctx);
6969
staticvoidinfo_cb(constSSL*ssl,inttype,intargs);
70+
staticintalpn_cb(SSL*ssl,
71+
constunsignedchar**out,
72+
unsignedchar*outlen,
73+
constunsignedchar*in,
74+
unsignedintinlen,
75+
void*userdata);
7076
staticboolinitialize_dh(SSL_CTX*context,boolisServerStart);
7177
staticboolinitialize_ecdh(SSL_CTX*context,boolisServerStart);
7278
staticconstchar*SSLerrmessage(unsigned longecode);
@@ -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+
constunsignedchar*selected;
587+
unsignedintlen;
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+
staticconstunsignedcharalpn_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+
staticint
1305+
alpn_cb(SSL*ssl,
1306+
constunsignedchar**out,
1307+
unsignedchar*outlen,
1308+
constunsignedchar*in,
1309+
unsignedintinlen,
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+
intretval;
1318+
1319+
Assert(userdata!=NULL);
1320+
Assert(out!=NULL);
1321+
Assert(outlen!=NULL);
1322+
Assert(in!=NULL);
1323+
1324+
retval=SSL_select_next_proto((unsignedchar**)out,outlen,
1325+
alpn_protos,sizeof(alpn_protos),
1326+
in,inlen);
1327+
if (*out==NULL||*outlen>sizeof(alpn_protos)||outlen <=0)
1328+
returnSSL_TLSEXT_ERR_NOACK;/* can't happen */
1329+
1330+
if (retval==OPENSSL_NPN_NEGOTIATED)
1331+
returnSSL_TLSEXT_ERR_OK;
1332+
elseif (retval==OPENSSL_NPN_NO_OVERLAP)
1333+
returnSSL_TLSEXT_ERR_NOACK;
1334+
else
1335+
returnSSL_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

‎src/backend/tcop/backend_startup.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,14 @@ ProcessSSLStartup(Port *port)
407407
}
408408
Assert(port->ssl_in_use);
409409

410+
if (!port->alpn_used)
411+
{
412+
ereport(COMMERROR,
413+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
414+
errmsg("received direct SSL connection request without ALPN protocol negotiation extension")));
415+
gotoreject;
416+
}
417+
410418
if (Trace_connection_negotiation)
411419
ereport(LOG,
412420
(errmsg("direct SSL connection accepted")));

‎src/bin/psql/command.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3882,18 +3882,21 @@ printSSLInfo(void)
38823882
constchar*protocol;
38833883
constchar*cipher;
38843884
constchar*compression;
3885+
constchar*alpn;
38853886

38863887
if (!PQsslInUse(pset.db))
38873888
return;/* no SSL */
38883889

38893890
protocol=PQsslAttribute(pset.db,"protocol");
38903891
cipher=PQsslAttribute(pset.db,"cipher");
38913892
compression=PQsslAttribute(pset.db,"compression");
3893+
alpn=PQsslAttribute(pset.db,"alpn");
38923894

3893-
printf(_("SSL connection (protocol: %s, cipher: %s, compression: %s)\n"),
3895+
printf(_("SSL connection (protocol: %s, cipher: %s, compression: %s, ALPN: %s)\n"),
38943896
protocol ?protocol :_("unknown"),
38953897
cipher ?cipher :_("unknown"),
3896-
(compression&&strcmp(compression,"off")!=0) ?_("on") :_("off"));
3898+
(compression&&strcmp(compression,"off")!=0) ?_("on") :_("off"),
3899+
alpn ?alpn :_("none"));
38973900
}
38983901

38993902
/*

‎src/include/libpq/libpq-be.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ typedef struct Port
203203
char*peer_cn;
204204
char*peer_dn;
205205
boolpeer_cert_valid;
206+
boolalpn_used;
206207

207208
/*
208209
* OpenSSL structures. (Keep these last so that the locations of other

‎src/include/libpq/pqcomm.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,25 @@ typedef struct CancelRequestPacket
139139
uint32cancelAuthCode;/* secret key to authorize cancel */
140140
}CancelRequestPacket;
141141

142+
/* Application-Layer Protocol Negotiation is required for direct connections
143+
* to avoid protocol confusion attacks (e.g https://alpaca-attack.com/).
144+
*
145+
* ALPN is specified in RFC 7301
146+
*
147+
* This string should be registered at:
148+
* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
149+
*
150+
* OpenSSL uses this wire-format for the list of alpn protocols even in the
151+
* API. Both server and client take the same format parameter but the client
152+
* actually sends it to the server as-is and the server it specifies the
153+
* preference order to use to choose the one selected to send back.
154+
*
155+
* c.f. https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_select_cb.html
156+
*
157+
* The #define can be used to initialize a char[] vector to use directly in the API
158+
*/
159+
#definePG_ALPN_PROTOCOL "TBD-pgsql"
160+
#definePG_ALPN_PROTOCOL_VECTOR { 9, 'T','B','D','-','p','g','s','q','l' }
142161

143162
/*
144163
* A client can also start by sending a SSL or GSSAPI negotiation request to

‎src/interfaces/libpq/fe-secure-openssl.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,9 @@ destroy_ssl_system(void)
885885
#endif
886886
}
887887

888+
/* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */
889+
staticunsignedcharalpn_protos[]=PG_ALPN_PROTOCOL_VECTOR;
890+
888891
/*
889892
*Create per-connection SSL object, and load the client certificate,
890893
*private key, and trusted CA certs.
@@ -1233,6 +1236,22 @@ initialize_SSL(PGconn *conn)
12331236
}
12341237
}
12351238

1239+
/* Set ALPN */
1240+
{
1241+
intretval;
1242+
1243+
retval=SSL_set_alpn_protos(conn->ssl,alpn_protos,sizeof(alpn_protos));
1244+
1245+
if (retval!=0)
1246+
{
1247+
char*err=SSLerrmessage(ERR_get_error());
1248+
1249+
libpq_append_conn_error(conn,"could not set ssl alpn extension: %s",err);
1250+
SSLerrfree(err);
1251+
return-1;
1252+
}
1253+
}
1254+
12361255
/*
12371256
* Read the SSL key. If a key is specified, treat it as an engine:key
12381257
* combination if there is colon present - we don't support files with
@@ -1754,6 +1773,7 @@ PQsslAttributeNames(PGconn *conn)
17541773
"cipher",
17551774
"compression",
17561775
"protocol",
1776+
"alpn",
17571777
NULL
17581778
};
17591779
staticconstchar*constempty_attrs[]= {NULL};
@@ -1808,6 +1828,21 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
18081828
if (strcmp(attribute_name,"protocol")==0)
18091829
returnSSL_get_version(conn->ssl);
18101830

1831+
if (strcmp(attribute_name,"alpn")==0)
1832+
{
1833+
constunsignedchar*data;
1834+
unsignedintlen;
1835+
staticcharalpn_str[256];/* alpn doesn't support longer than 255
1836+
* bytes */
1837+
1838+
SSL_get0_alpn_selected(conn->ssl,&data,&len);
1839+
if (data==NULL||len==0||len>sizeof(alpn_str)-1)
1840+
returnNULL;
1841+
memcpy(alpn_str,data,len);
1842+
alpn_str[len]=0;
1843+
returnalpn_str;
1844+
}
1845+
18111846
returnNULL;/* unknown attribute */
18121847
}
18131848

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp