{"id":"97a83ccf85cc32d7","repo":"jackc/pgx","slug":"no-peer-certificates-for-channel-binding","errorCode":null,"errorMessage":"no peer certificates for channel binding","messagePattern":"no peer certificates for channel binding","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgconn/auth_scram.go","lineNumber":381,"sourceCode":"\tbuf := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof)))\n\tbase64.StdEncoding.Encode(buf, clientProof)\n\treturn buf\n}\n\nfunc computeServerSignature(saltedPassword, authMessage []byte) []byte {\n\tserverKey := computeHMAC(saltedPassword, []byte(\"Server Key\"))\n\tserverSignature := computeHMAC(serverKey, authMessage)\n\tbuf := make([]byte, base64.StdEncoding.EncodedLen(len(serverSignature)))\n\tbase64.StdEncoding.Encode(buf, serverSignature)\n\treturn buf\n}\n\n// Get the server certificate hash for SCRAM channel binding type\n// tls-server-end-point.\nfunc getTLSCertificateHash(conn *tls.Conn) ([]byte, error) {\n\tstate := conn.ConnectionState()\n\tif len(state.PeerCertificates) == 0 {\n\t\treturn nil, errors.New(\"no peer certificates for channel binding\")\n\t}\n\n\tcert := state.PeerCertificates[0]\n\n\t// Per RFC 5929 section 4.1: If the certificate's signatureAlgorithm uses\n\t// MD5 or SHA-1, use SHA-256. Otherwise use the hash from the signature\n\t// algorithm.\n\t//\n\t// See: https://www.rfc-editor.org/rfc/rfc5929.html#section-4.1\n\tvar h hash.Hash\n\tswitch cert.SignatureAlgorithm {\n\tcase x509.MD5WithRSA, x509.SHA1WithRSA, x509.ECDSAWithSHA1:\n\t\th = sha256.New()\n\tcase x509.SHA256WithRSA, x509.SHA256WithRSAPSS, x509.ECDSAWithSHA256:\n\t\th = sha256.New()\n\tcase x509.SHA384WithRSA, x509.SHA384WithRSAPSS, x509.ECDSAWithSHA384:\n\t\th = sha512.New384()\n\tcase x509.SHA512WithRSA, x509.SHA512WithRSAPSS, x509.ECDSAWithSHA512:","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/auth_scram.go#L363-L399","documentation":"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.","triggerScenarios":"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.","commonSituations":"Internal mesh/proxy using PSK or anonymous cipher suites; misconfigured TLS termination that presents no server certificate; exotic TLS configs.","solutions":["Ensure the server presents an X.509 certificate during the TLS handshake.","If binding is not required, set Config.ChannelBinding to \"\" or \"disable\".","Use a normal certificate-based TLS deployment end-to-end."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure the server presents a cert before relying on channel binding.\n// You can preflight by dialing TLS separately, or simply avoid requiring binding\n// when the deployment uses PSK/anonymous TLS.\nfunc shouldRequireBinding(serverPresentsCert bool) string {\n    if serverPresentsCert {\n        return \"require\"\n    }\n    return \"\" // auto\n}","typeGuard":null,"tryCatchPattern":"if err := connect(); err != nil && strings.Contains(err.Error(), \"no peer certificates for channel binding\") {\n    cc.ChannelBinding = \"\" // relax and retry without binding\n}","preventionTips":["Ensure servers present X.509 certificates during TLS.","Do not set ChannelBinding=\"require\" with PSK or anonymous TLS.","Use standard certificate-based TLS end-to-end."],"tags":["tls","channel-binding","certificates","security","scram"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}