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

Commitd3fb72e

Browse files
committed
Implement channel binding tls-server-end-point for SCRAM
This adds a second standard channel binding type for SCRAM. It ismainly intended for third-party clients that cannot implementtls-unique, for example JDBC.Author: Michael Paquier <michael.paquier@gmail.com>
1 parent39cfe86 commitd3fb72e

File tree

9 files changed

+189
-12
lines changed

9 files changed

+189
-12
lines changed

‎doc/src/sgml/protocol.sgml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,9 +1575,13 @@ the password is in.
15751575

15761576
<para>
15771577
<firstterm>Channel binding</firstterm> is supported in PostgreSQL builds with
1578-
SSL support. The SASL mechanism name for SCRAM with channel binding
1579-
is <literal>SCRAM-SHA-256-PLUS</literal>. The only channel binding type
1580-
supported at the moment is <literal>tls-unique</literal>, defined in RFC 5929.
1578+
SSL support. The SASL mechanism name for SCRAM with channel binding is
1579+
<literal>SCRAM-SHA-256-PLUS</literal>. Two channel binding types are
1580+
supported: <literal>tls-unique</literal> and
1581+
<literal>tls-server-end-point</literal>, both defined in RFC 5929. Clients
1582+
should use <literal>tls-unique</literal> if they can support it.
1583+
<literal>tls-server-end-point</literal> is intended for third-party clients
1584+
that cannot support <literal>tls-unique</literal> for some reason.
15811585
</para>
15821586

15831587
<procedure>
@@ -1597,9 +1601,10 @@ supported at the moment is <literal>tls-unique</literal>, defined in RFC 5929.
15971601
indicates the chosen mechanism, <literal>SCRAM-SHA-256</literal> or
15981602
<literal>SCRAM-SHA-256-PLUS</literal>. (A client is free to choose either
15991603
mechanism, but for better security it should choose the channel-binding
1600-
variant if it can support it.) In the Initial Client response field,
1601-
the message contains the SCRAM
1602-
<structname>client-first-message</structname>.
1604+
variant if it can support it.) In the Initial Client response field, the
1605+
message contains the SCRAM <structname>client-first-message</structname>.
1606+
The <structname>client-first-message</structname> also contains the channel
1607+
binding type chosen by the client.
16031608
</para>
16041609
</step>
16051610
<step id="scram-server-first">

‎src/backend/libpq/auth-scram.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -849,13 +849,14 @@ read_client_first_message(scram_state *state, char *input)
849849
}
850850

851851
/*
852-
* Read value provided by client; only tls-unique issupported
853-
*for now. (It is not safe to printthename of an
854-
*unsupported binding type in the error message. Pranksters
855-
*could print arbitrary strings into thelog that way.)
852+
* Read value provided by client. (It isnot safe to print
853+
*the name of an unsupported binding type intheerror
854+
*message. Pranksters could print arbitrary strings into the
855+
* log that way.)
856856
*/
857857
channel_binding_type=read_attr_value(&input,'p');
858-
if (strcmp(channel_binding_type,SCRAM_CHANNEL_BINDING_TLS_UNIQUE)!=0)
858+
if (strcmp(channel_binding_type,SCRAM_CHANNEL_BINDING_TLS_UNIQUE)!=0&&
859+
strcmp(channel_binding_type,SCRAM_CHANNEL_BINDING_TLS_END_POINT)!=0)
859860
ereport(ERROR,
860861
(errcode(ERRCODE_PROTOCOL_VIOLATION),
861862
(errmsg("unsupported SCRAM channel-binding type"))));
@@ -1114,6 +1115,15 @@ read_client_final_message(scram_state *state, char *input)
11141115
{
11151116
#ifdefUSE_SSL
11161117
cbind_data=be_tls_get_peer_finished(state->port,&cbind_data_len);
1118+
#endif
1119+
}
1120+
elseif (strcmp(state->channel_binding_type,
1121+
SCRAM_CHANNEL_BINDING_TLS_END_POINT)==0)
1122+
{
1123+
/* Fetch hash data of server's SSL certificate */
1124+
#ifdefUSE_SSL
1125+
cbind_data=be_tls_get_certificate_hash(state->port,
1126+
&cbind_data_len);
11171127
#endif
11181128
}
11191129
else

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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,67 @@ be_tls_get_peer_finished(Port *port, size_t *len)
12391239
returnresult;
12401240
}
12411241

1242+
/*
1243+
* Get the server certificate hash for SCRAM channel binding type
1244+
* tls-server-end-point.
1245+
*
1246+
* The result is a palloc'd hash of the server certificate with its
1247+
* size, and NULL if there is no certificate available.
1248+
*/
1249+
char*
1250+
be_tls_get_certificate_hash(Port*port,size_t*len)
1251+
{
1252+
X509*server_cert;
1253+
char*cert_hash;
1254+
constEVP_MD*algo_type=NULL;
1255+
unsignedcharhash[EVP_MAX_MD_SIZE];/* size for SHA-512 */
1256+
unsignedinthash_size;
1257+
intalgo_nid;
1258+
1259+
*len=0;
1260+
server_cert=SSL_get_certificate(port->ssl);
1261+
if (server_cert==NULL)
1262+
returnNULL;
1263+
1264+
/*
1265+
* Get the signature algorithm of the certificate to determine the
1266+
* hash algorithm to use for the result.
1267+
*/
1268+
if (!OBJ_find_sigid_algs(X509_get_signature_nid(server_cert),
1269+
&algo_nid,NULL))
1270+
elog(ERROR,"could not determine server certificate signature algorithm");
1271+
1272+
/*
1273+
* The TLS server's certificate bytes need to be hashed with SHA-256 if
1274+
* its signature algorithm is MD5 or SHA-1 as per RFC 5929
1275+
* (https://tools.ietf.org/html/rfc5929#section-4.1). If something else
1276+
* is used, the same hash as the signature algorithm is used.
1277+
*/
1278+
switch (algo_nid)
1279+
{
1280+
caseNID_md5:
1281+
caseNID_sha1:
1282+
algo_type=EVP_sha256();
1283+
break;
1284+
default:
1285+
algo_type=EVP_get_digestbynid(algo_nid);
1286+
if (algo_type==NULL)
1287+
elog(ERROR,"could not find digest for NID %s",
1288+
OBJ_nid2sn(algo_nid));
1289+
break;
1290+
}
1291+
1292+
/* generate and save the certificate hash */
1293+
if (!X509_digest(server_cert,algo_type,hash,&hash_size))
1294+
elog(ERROR,"could not generate server certificate hash");
1295+
1296+
cert_hash=palloc(hash_size);
1297+
memcpy(cert_hash,hash,hash_size);
1298+
*len=hash_size;
1299+
1300+
returncert_hash;
1301+
}
1302+
12421303
/*
12431304
* Convert an X509 subject name to a cstring.
12441305
*

‎src/include/common/scram-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
/* Channel binding types */
2323
#defineSCRAM_CHANNEL_BINDING_TLS_UNIQUE "tls-unique"
24+
#defineSCRAM_CHANNEL_BINDING_TLS_END_POINT"tls-server-end-point"
2425

2526
/* Length of SCRAM keys (client and server) */
2627
#defineSCRAM_KEY_LENPG_SHA256_DIGEST_LENGTH

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ extern void be_tls_get_version(Port *port, char *ptr, size_t len);
210210
externvoidbe_tls_get_cipher(Port*port,char*ptr,size_tlen);
211211
externvoidbe_tls_get_peerdn_name(Port*port,char*ptr,size_tlen);
212212
externchar*be_tls_get_peer_finished(Port*port,size_t*len);
213+
externchar*be_tls_get_certificate_hash(Port*port,size_t*len);
213214
#endif
214215

215216
externProtocolVersionFrontendProtocol;

‎src/interfaces/libpq/fe-auth-scram.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,21 @@ build_client_final_message(fe_scram_state *state)
444444
cbind_data=pgtls_get_finished(state->conn,&cbind_data_len);
445445
if (cbind_data==NULL)
446446
gotooom_error;
447+
#endif
448+
}
449+
elseif (strcmp(conn->scram_channel_binding,
450+
SCRAM_CHANNEL_BINDING_TLS_END_POINT)==0)
451+
{
452+
/* Fetch hash data of server's SSL certificate */
453+
#ifdefUSE_SSL
454+
cbind_data=
455+
pgtls_get_peer_certificate_hash(state->conn,
456+
&cbind_data_len);
457+
if (cbind_data==NULL)
458+
{
459+
/* error message is already set on error */
460+
returnNULL;
461+
}
447462
#endif
448463
}
449464
else

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

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,86 @@ pgtls_get_finished(PGconn *conn, size_t *len)
419419
returnresult;
420420
}
421421

422+
/*
423+
* Get the hash of the server certificate, for SCRAM channel binding type
424+
* tls-server-end-point.
425+
*
426+
* NULL is sent back to the caller in the event of an error, with an
427+
* error message for the caller to consume.
428+
*/
429+
char*
430+
pgtls_get_peer_certificate_hash(PGconn*conn,size_t*len)
431+
{
432+
X509*peer_cert;
433+
constEVP_MD*algo_type;
434+
unsignedcharhash[EVP_MAX_MD_SIZE];/* size for SHA-512 */
435+
unsignedinthash_size;
436+
intalgo_nid;
437+
char*cert_hash;
438+
439+
*len=0;
440+
441+
if (!conn->peer)
442+
returnNULL;
443+
444+
peer_cert=conn->peer;
445+
446+
/*
447+
* Get the signature algorithm of the certificate to determine the hash
448+
* algorithm to use for the result.
449+
*/
450+
if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert),
451+
&algo_nid,NULL))
452+
{
453+
printfPQExpBuffer(&conn->errorMessage,
454+
libpq_gettext("could not determine server certificate signature algorithm\n"));
455+
returnNULL;
456+
}
457+
458+
/*
459+
* The TLS server's certificate bytes need to be hashed with SHA-256 if
460+
* its signature algorithm is MD5 or SHA-1 as per RFC 5929
461+
* (https://tools.ietf.org/html/rfc5929#section-4.1). If something else
462+
* is used, the same hash as the signature algorithm is used.
463+
*/
464+
switch (algo_nid)
465+
{
466+
caseNID_md5:
467+
caseNID_sha1:
468+
algo_type=EVP_sha256();
469+
break;
470+
default:
471+
algo_type=EVP_get_digestbynid(algo_nid);
472+
if (algo_type==NULL)
473+
{
474+
printfPQExpBuffer(&conn->errorMessage,
475+
libpq_gettext("could not find digest for NID %s\n"),
476+
OBJ_nid2sn(algo_nid));
477+
returnNULL;
478+
}
479+
break;
480+
}
481+
482+
if (!X509_digest(peer_cert,algo_type,hash,&hash_size))
483+
{
484+
printfPQExpBuffer(&conn->errorMessage,
485+
libpq_gettext("could not generate peer certificate hash\n"));
486+
returnNULL;
487+
}
488+
489+
/* save result */
490+
cert_hash=malloc(hash_size);
491+
if (cert_hash==NULL)
492+
{
493+
printfPQExpBuffer(&conn->errorMessage,
494+
libpq_gettext("out of memory\n"));
495+
returnNULL;
496+
}
497+
memcpy(cert_hash,hash,hash_size);
498+
*len=hash_size;
499+
500+
returncert_hash;
501+
}
422502

423503
/* ------------------------------------------------------------ */
424504
/*OpenSSL specific code*/

‎src/interfaces/libpq/libpq-int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len);
672672
externboolpgtls_read_pending(PGconn*conn);
673673
externssize_tpgtls_write(PGconn*conn,constvoid*ptr,size_tlen);
674674
externchar*pgtls_get_finished(PGconn*conn,size_t*len);
675+
externchar*pgtls_get_peer_certificate_hash(PGconn*conn,size_t*len);
675676

676677
/*
677678
* this is so that we can check if a connection is non-blocking internally

‎src/test/ssl/t/002_scram.pl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use warnings;
55
use PostgresNode;
66
use TestLib;
7-
use Test::Moretests=>4;
7+
use Test::Moretests=>5;
88
use ServerSetup;
99
use File::Copy;
1010

@@ -45,6 +45,9 @@
4545
test_connect_ok($common_connstr,
4646
"scram_channel_binding=''",
4747
"SCRAM authentication without channel binding");
48+
test_connect_ok($common_connstr,
49+
"scram_channel_binding=tls-server-end-point",
50+
"SCRAM authentication with tls-server-end-point as channel binding");
4851
test_connect_fails($common_connstr,
4952
"scram_channel_binding=not-exists",
5053
"SCRAM authentication with invalid channel binding");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp