hyperledger/fabric · error

verifying tls %s cert with serial number %d

Error message

verifying tls %s cert with serial number %d

What it means

In etcdraft/util.go, before joining or verifying consenter TLS certificates, each peer's client/server certificate is verified against the channel's root CAs. If x509 Certificate.Verify fails with anything other than an (optionally ignored) expiry error, it is wrapped with the cert type (client/server), the serial number, and the underlying x509 error. The library throws it because a TLS cert that cannot chain to the channel trust anchors makes the consenter unusable for secure communication.

Source

Thrown at orderer/consensus/etcdraft/util.go:335

	}, nil
}

// validateConsenterTLSCerts decodes PEM cert, parses and validates it.
func validateConsenterTLSCerts(c *etcdraft.Consenter, opts x509.VerifyOptions, ignoreExpiration bool) error {
	clientCert, err := parseCertificateFromBytes(c.GetClientTlsCert())
	if err != nil {
		return errors.Wrapf(err, "parsing tls client cert of %s:%d", c.GetHost(), c.GetPort())
	}

	serverCert, err := parseCertificateFromBytes(c.GetServerTlsCert())
	if err != nil {
		return errors.Wrapf(err, "parsing tls server cert of %s:%d", c.GetHost(), c.GetPort())
	}

	verify := func(certType string, cert *x509.Certificate, opts x509.VerifyOptions) error {
		if _, err := cert.Verify(opts); err != nil {
			if validationRes, ok := err.(x509.CertificateInvalidError); !ok || (!ignoreExpiration || validationRes.Reason != x509.Expired) {
				return errors.Wrapf(err, "verifying tls %s cert with serial number %d", certType, cert.SerialNumber)
			}
		}
		return nil
	}

	if err := verify("client", clientCert, opts); err != nil {
		return err
	}
	if err := verify("server", serverCert, opts); err != nil {
		return err
	}

	return nil
}

// ConsenterCertificate denotes a TLS certificate of a consenter
type ConsenterCertificate struct {
	ConsenterCertificate []byte

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Add the issuing CA of the failing cert (serial shown in the message) to the channel's TLS root CAs (and intermediates if chaining requires it) via a channel config update
  2. Regenerate the consenter TLS certificate from the organization's MSP CA so it chains to the configured roots
  3. Ensure KeyUsage/ExtKeyUsage on the cert matches its role (serverAuth/server, clientAuth/client)
  4. Fix host clock skew (NTP) or reissue the cert if it is expired or not yet valid

Example fix

// before: consenter TLS cert signed by CA absent from channel config
// after: configtx update adding the CA
// channelconfig: Orderer.Organizations.<MSP>.TLSRootCerts += new-ca.pem
// then regenerate consenter cert:
// fabric-ca-client gencsr --tls.keyfiles tls.key --csr.hosts orderer.example.com
Defensive patterns

Strategy: validation

Validate before calling

func validateTLSCert(certPEM, certType string, roots *x509.CertPool, serverName string) error {
    block, _ := pem.Decode([]byte(certPEM))
    if block == nil { return errors.New("not PEM") }
    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil { return err }
    opts := x509.VerifyOptions{Roots: roots, DNSName: serverName}
    if certType == "client" { opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} }
    _, err = cert.Verify(opts)
    return err
}

Prevention

When it happens

Trigger: Calling channels/consenter verification (e.g. cluster verification in etcdraft) where a consenter's TLS client or server certificate fails Verify against the supplied VerifyOptions: unknown CA, wrong key usage, expired/not-yet-valid cert, or hostname mismatch.

Common situations: Orderer TLS certificates rotated with new intermediate CAs not listed in the channel config's TLS root CAs; cert generated for a different hostname than the consenter's configured host:port; system clock skew making a valid cert appear expired; mixing Org1-issued certs into an Org2 consenter config.

Understand the failure class

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/7513fef520dce276. Report an issue: GitHub.