jackc/pgx · error

no peer certificates for channel binding

Error message

no peer certificates for channel binding

What it means

Returned by getTLSCertificateHash when the TLS connection state has zero peer certificates. Channel binding via tls-server-end-point requires the server's leaf certificate to hash; with no certificate present, the hash cannot be computed. This is an internal error surfaced when channel binding is attempted over an anonymous or PSK TLS session.

Source

Thrown at pgconn/auth_scram.go:381

	buf := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof)))
	base64.StdEncoding.Encode(buf, clientProof)
	return buf
}

func computeServerSignature(saltedPassword, authMessage []byte) []byte {
	serverKey := computeHMAC(saltedPassword, []byte("Server Key"))
	serverSignature := computeHMAC(serverKey, authMessage)
	buf := make([]byte, base64.StdEncoding.EncodedLen(len(serverSignature)))
	base64.StdEncoding.Encode(buf, serverSignature)
	return buf
}

// Get the server certificate hash for SCRAM channel binding type
// tls-server-end-point.
func getTLSCertificateHash(conn *tls.Conn) ([]byte, error) {
	state := conn.ConnectionState()
	if len(state.PeerCertificates) == 0 {
		return nil, errors.New("no peer certificates for channel binding")
	}

	cert := state.PeerCertificates[0]

	// Per RFC 5929 section 4.1: If the certificate's signatureAlgorithm uses
	// MD5 or SHA-1, use SHA-256. Otherwise use the hash from the signature
	// algorithm.
	//
	// See: https://www.rfc-editor.org/rfc/rfc5929.html#section-4.1
	var h hash.Hash
	switch cert.SignatureAlgorithm {
	case x509.MD5WithRSA, x509.SHA1WithRSA, x509.ECDSAWithSHA1:
		h = sha256.New()
	case x509.SHA256WithRSA, x509.SHA256WithRSAPSS, x509.ECDSAWithSHA256:
		h = sha256.New()
	case x509.SHA384WithRSA, x509.SHA384WithRSAPSS, x509.ECDSAWithSHA384:
		h = sha512.New384()
	case x509.SHA512WithRSA, x509.SHA512WithRSAPSS, x509.ECDSAWithSHA512:

View on GitHub (pinned to ec1a0befd2)

Solutions

  1. Ensure the server presents an X.509 certificate during the TLS handshake.
  2. If binding is not required, set Config.ChannelBinding to "" or "disable".
  3. Use a normal certificate-based TLS deployment end-to-end.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the server presents a cert before relying on channel binding.
// You can preflight by dialing TLS separately, or simply avoid requiring binding
// when the deployment uses PSK/anonymous TLS.
func shouldRequireBinding(serverPresentsCert bool) string {
    if serverPresentsCert {
        return "require"
    }
    return "" // auto
}

Try / catch

if err := connect(); err != nil && strings.Contains(err.Error(), "no peer certificates for channel binding") {
    cc.ChannelBinding = "" // relax and retry without binding
}

Prevention

When it happens

Trigger: A TLS connection (*tls.Conn) whose ConnectionState().PeerCertificates is empty, encountered while deriving channel binding data in scramAuth. Happens with anonymous TLS (TLS_NULL_WITH_NULL-style), TLS-PSK, or when a proxy completes TLS without forwarding a server cert.

Common situations: Internal mesh/proxy using PSK or anonymous cipher suites; misconfigured TLS termination that presents no server certificate; exotic TLS configs.

Related errors


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/97a83ccf85cc32d7.json. Report an issue: GitHub.