@@ -419,6 +419,86 @@ pgtls_get_finished(PGconn *conn, size_t *len)
419419 return result ;
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+ const EVP_MD * algo_type ;
434+ unsigned char hash [EVP_MAX_MD_SIZE ]; /* size for SHA-512 */
435+ unsigned int hash_size ;
436+ int algo_nid ;
437+ char * cert_hash ;
438+
439+ * len = 0 ;
440+
441+ if (!conn -> peer )
442+ return NULL ;
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+ return NULL ;
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+ case NID_md5 :
467+ case NID_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+ return NULL ;
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+ return NULL ;
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+ return NULL ;
496+ }
497+ memcpy (cert_hash , hash , hash_size );
498+ * len = hash_size ;
499+
500+ return cert_hash ;
501+ }
422502
423503/* ------------------------------------------------------------ */
424504/* OpenSSL specific code */
0 commit comments