{"record":{"id":"3726d734b4bea294","repo":"hyperledger/fabric","slug":"certificate-extracted-from-tls-connection-isn-t-au","errorCode":null,"errorMessage":"certificate extracted from TLS connection isn't authorized","messagePattern":"certificate extracted from TLS connection isn't authorized","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/comm.go","lineNumber":108,"sourceCode":"\t\treturn nil, errors.Errorf(\"badly formatted message, cannot extract channel\")\n\t}\n\n\tc.Lock.RLock()\n\tmapping, exists := c.Chan2Members[channel]\n\tc.Lock.RUnlock()\n\n\tif !exists {\n\t\treturn nil, errors.Errorf(\"channel %s doesn't exist\", channel)\n\t}\n\n\tcert := util.ExtractRawCertificateFromContext(ctx)\n\tif len(cert) == 0 {\n\t\treturn nil, errors.Errorf(\"no TLS certificate sent\")\n\t}\n\n\tstub := mapping.LookupByClientCert(cert)\n\tif stub == nil {\n\t\treturn nil, errors.Errorf(\"certificate extracted from TLS connection isn't authorized\")\n\t}\n\treturn &requestContext{\n\t\tchannel: channel,\n\t\tsender:  stub.ID,\n\t}, nil\n}\n\n// Remote obtains a RemoteContext linked to the destination node on the context\n// of a given channel\nfunc (c *Comm) Remote(channel string, id uint64) (*RemoteContext, error) {\n\tc.Lock.RLock()\n\tdefer c.Lock.RUnlock()\n\n\tif c.shutdown {\n\t\treturn nil, errors.New(\"communication has been shut down\")\n\t}\n\n\tmapping, exists := c.Chan2Members[channel]","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/comm.go#L90-L126","documentation":"A TLS client certificate was present in the request context, but mapping.LookupByClientCert(cert) found no stub in the channel's member mapping matching that certificate. The certificate is not one of the authorized cluster members (orderer nodes) configured for the channel, so the sender's identity is rejected.","triggerScenarios":"DispatchSubmit or DispatchConsensus receives a request whose TLS cert doesn't match any entry in the channel's Cluster membership (cluster.Server root certs / members list) — e.g. an unauthorized node, a renewed cert not yet in channel config, or cert loaded in the wrong order (DER vs PEM byte mismatch in lookup).","commonSituations":"Orderer TLS certificate rotated/re-enrolled but the channel's cluster membership config not updated; joining a new orderer whose cert wasn't added via config update; connecting with the server cert instead of the client cert; CA mismatch between sender cert and configured members.","solutions":["Verify the sender's TLS cert is included in the channel's cluster members configuration (orderer addresses/certs) via a config update","If certs were rotated, update the channel config with the new TLS certs and restart both ends","Ensure the orderer's General.TLS.Certificate matches the cert registered in the channel config (not a stale/other node's cert)","Confirm both ends trust the same TLS CA and the client cert (not server cert) is presented"],"exampleFix":"// before (channel config missing new orderer's TLS cert)\nmembers := []Member{oldOrdererCert}\n// after — add the new orderer's TLS cert to channel config\nconfigUpdate := addClusterMemberTLS(members, newOrdererTLSCert)\nchannelConfigUpdate(\"mychannel\", configUpdate)","handlingStrategy":"type-guard","validationCode":"// Sender-side: confirm your TLS cert matches one in the channel's cluster members\nfunc certInChannelConfig(certPEM []byte, channelConfig *common.Config) bool {\n    members := channelConfig.ChannelGroup.Groups[\"Orderer\"].Values\n    tlsCerts := string(members[\"Cluster\"].Value.Value)\n    return strings.Contains(tlsCerts, strings.TrimSpace(string(certPEM)))\n}","typeGuard":"func isAuthorizedClusterStub(stub *Stub) bool {\n    return stub != nil && stub.ID != \"\"\n}\n// usage: only proceed when guard passes\nif stub := mapping.LookupByClientCert(cert); isAuthorizedClusterStub(stub) { ... }","tryCatchPattern":"if _, err := comm.Remote(channel, id); err != nil {\n    if strings.Contains(err.Error(), \"isn't authorized\") {\n        // trigger cert/config sync: fetch latest channel config and compare TLS certs\n        return fmt.Errorf(\"orderer TLS cert not in channel cluster config: %w\", err)\n    }\n}","preventionTips":["Whenever re-enrolling or rotating an orderer TLS cert, immediately update the channel config","Use the same CA for all cluster member certs and keep CA bundles in sync","Ensure the orderer presents the exact cert registered in channel config (byte-identical DER)","After adding a new orderer node, verify LookupByClientCert succeeds with a test Step call"],"tags":["tls","authorization","hyperledger-fabric","cluster"],"backgroundTag":"tls-certificate-unauthorized","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"}