{"record":{"id":"77ec127e9aad5d34","repo":"hyperledger/fabric","slug":"parsing-tls-client-cert-of-s-d","errorCode":null,"errorMessage":"parsing tls client cert of %s:%d","messagePattern":"parsing tls client cert of (.+?):(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":324,"sourceCode":"\t\t\ttlsIntermediates.AddCert(cert)\n\t\t}\n\t}\n\n\treturn x509.VerifyOptions{\n\t\tRoots:         tlsRoots,\n\t\tIntermediates: tlsIntermediates,\n\t\tKeyUsages: []x509.ExtKeyUsage{\n\t\t\tx509.ExtKeyUsageClientAuth,\n\t\t\tx509.ExtKeyUsageServerAuth,\n\t\t},\n\t}, nil\n}\n\n// validateConsenterTLSCerts decodes PEM cert, parses and validates it.\nfunc validateConsenterTLSCerts(c *etcdraft.Consenter, opts x509.VerifyOptions, ignoreExpiration bool) error {\n\tclientCert, err := parseCertificateFromBytes(c.GetClientTlsCert())\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"parsing tls client cert of %s:%d\", c.GetHost(), c.GetPort())\n\t}\n\n\tserverCert, err := parseCertificateFromBytes(c.GetServerTlsCert())\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"parsing tls server cert of %s:%d\", c.GetHost(), c.GetPort())\n\t}\n\n\tverify := func(certType string, cert *x509.Certificate, opts x509.VerifyOptions) error {\n\t\tif _, err := cert.Verify(opts); err != nil {\n\t\t\tif validationRes, ok := err.(x509.CertificateInvalidError); !ok || (!ignoreExpiration || validationRes.Reason != x509.Expired) {\n\t\t\t\treturn errors.Wrapf(err, \"verifying tls %s cert with serial number %d\", certType, cert.SerialNumber)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tif err := verify(\"client\", clientCert, opts); err != nil {\n\t\treturn err","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L306-L342","documentation":"validateConsenterTLSCerts parses a consenter's client TLS cert from channel config with parseCertificateFromBytes; a parse failure is wrapped with 'parsing tls client cert of <host>:<port>'. It means the client_tls_cert bytes of the identified consenter are missing PEM data or not a valid ASN.1 X.509 certificate, blocking consensus metadata validation.","triggerScenarios":"VerifyConfigMetadata or ValidateConsensusMetadata iterating etcdraft consenters; consenter c has a GetClientTlsCert() whose PEM decode yields no block or whose DER fails x509.ParseCertificate; the wrap adds the consenter host:port so the bad node is identifiable.","commonSituations":"configtx.yaml entry for an orderer has an empty or wrong client_tls_cert (key, CSR, or TLS-CA cert pasted in orderer certs field); node re-enrolled with new certs but config update not applied; manual base64 editing corrupted the value.","solutions":["Fix the client_tls_cert for the consenter at host:port in configtx.yaml with a valid base64 PEM certificate and re-run configtxgen/config update","Confirm the cert was generated for the client TLS role (tls/client.crt) and matches the consenter's TLS keypair","Decode and check the failing bytes (openssl x509 -inform pem) to see if the PEM is empty/corrupt","Re-enroll the orderer node via fabric-ca so valid client TLS certs are issued, then regenerate channel config"],"exampleFix":"// before: server cert reused for client field\nclient_tls_cert: \"$(base64 orderer.example.com/tls/server.crt)\"\n// after\nclient_tls_cert: \"$(base64 orderer.example.com/tls/client.crt)\"","handlingStrategy":"validation","validationCode":"// validate each consenter's client TLS cert before config update\nfor _, c := range metadata.Consenters {\n    if err := validateTLSCertBytes(c.ClientTlsCert); err != nil {\n        return fmt.Errorf(\"consenter %s:%d has invalid client tls cert: %w\", c.Host, c.Port, err)\n    }\n}","typeGuard":"func hasValidClientTLSCert(c *etcdraft.Consenter) bool {\n    block, _ := pem.Decode(c.GetClientTlsCert())\n    return block != nil && block.Type == \"CERTIFICATE\"\n}","tryCatchPattern":"if err := ValidateConsensusMetadata(m, l, nil); err != nil {\n    if strings.Contains(err.Error(), \"parsing tls client cert of\") {\n        return fmt.Errorf(\"a consenter's client_tls_cert is malformed: %w\", err)\n    }\n    return err\n}","preventionTips":["Fill client_tls_cert from the node's tls/client.crt, never from server.crt or .key","Base64-encode certs with `base64 -w0` to avoid newline corruption","Keep host:port in consenter config matching the node that owns the cert","Re-run configtxgen after any node re-enrollment to refresh cert fields"],"tags":["x509","tls","etcdraft","consenter","hyperledger-fabric"],"backgroundTag":"invalid-consenter-tls-cert","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}