mirror of
https://github.com/postgres/postgres.git
synced 2025-08-25 20:23:07 +03:00
Implement channel binding tls-server-end-point for SCRAM
This adds a second standard channel binding type for SCRAM. It is mainly intended for third-party clients that cannot implement tls-unique, for example JDBC. Author: Michael Paquier <michael.paquier@gmail.com>
This commit is contained in:
@@ -444,6 +444,21 @@ build_client_final_message(fe_scram_state *state)
|
||||
cbind_data = pgtls_get_finished(state->conn, &cbind_data_len);
|
||||
if (cbind_data == NULL)
|
||||
goto oom_error;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(conn->scram_channel_binding,
|
||||
SCRAM_CHANNEL_BINDING_TLS_END_POINT) == 0)
|
||||
{
|
||||
/* Fetch hash data of server's SSL certificate */
|
||||
#ifdef USE_SSL
|
||||
cbind_data =
|
||||
pgtls_get_peer_certificate_hash(state->conn,
|
||||
&cbind_data_len);
|
||||
if (cbind_data == NULL)
|
||||
{
|
||||
/* error message is already set on error */
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@@ -419,6 +419,86 @@ pgtls_get_finished(PGconn *conn, size_t *len)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the hash of the server certificate, for SCRAM channel binding type
|
||||
* tls-server-end-point.
|
||||
*
|
||||
* NULL is sent back to the caller in the event of an error, with an
|
||||
* error message for the caller to consume.
|
||||
*/
|
||||
char *
|
||||
pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
|
||||
{
|
||||
X509 *peer_cert;
|
||||
const EVP_MD *algo_type;
|
||||
unsigned char hash[EVP_MAX_MD_SIZE]; /* size for SHA-512 */
|
||||
unsigned int hash_size;
|
||||
int algo_nid;
|
||||
char *cert_hash;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (!conn->peer)
|
||||
return NULL;
|
||||
|
||||
peer_cert = conn->peer;
|
||||
|
||||
/*
|
||||
* Get the signature algorithm of the certificate to determine the hash
|
||||
* algorithm to use for the result.
|
||||
*/
|
||||
if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert),
|
||||
&algo_nid, NULL))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not determine server certificate signature algorithm\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The TLS server's certificate bytes need to be hashed with SHA-256 if
|
||||
* its signature algorithm is MD5 or SHA-1 as per RFC 5929
|
||||
* (https://tools.ietf.org/html/rfc5929#section-4.1). If something else
|
||||
* is used, the same hash as the signature algorithm is used.
|
||||
*/
|
||||
switch (algo_nid)
|
||||
{
|
||||
case NID_md5:
|
||||
case NID_sha1:
|
||||
algo_type = EVP_sha256();
|
||||
break;
|
||||
default:
|
||||
algo_type = EVP_get_digestbynid(algo_nid);
|
||||
if (algo_type == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not find digest for NID %s\n"),
|
||||
OBJ_nid2sn(algo_nid));
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!X509_digest(peer_cert, algo_type, hash, &hash_size))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not generate peer certificate hash\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* save result */
|
||||
cert_hash = malloc(hash_size);
|
||||
if (cert_hash == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("out of memory\n"));
|
||||
return NULL;
|
||||
}
|
||||
memcpy(cert_hash, hash, hash_size);
|
||||
*len = hash_size;
|
||||
|
||||
return cert_hash;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* OpenSSL specific code */
|
||||
|
@@ -672,6 +672,7 @@ extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len);
|
||||
extern bool pgtls_read_pending(PGconn *conn);
|
||||
extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len);
|
||||
extern char *pgtls_get_finished(PGconn *conn, size_t *len);
|
||||
extern char *pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len);
|
||||
|
||||
/*
|
||||
* this is so that we can check if a connection is non-blocking internally
|
||||
|
Reference in New Issue
Block a user