1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +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:
Peter Eisentraut
2018-01-04 15:18:39 -05:00
parent 39cfe86195
commit d3fb72ea6d
9 changed files with 189 additions and 12 deletions

View File

@ -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 */