{"record":{"id":"22a3287a145d349e","repo":"hyperledger/fabric","slug":"signature-mismatch","errorCode":null,"errorMessage":"signature mismatch","messagePattern":"signature mismatch","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/clusterservice.go","lineNumber":177,"sourceCode":"\t}\n\n\ttoIdentity := membership.MemberMapping[authReq.ToId]\n\tif toIdentity == nil {\n\t\treturn nil, errors.Errorf(\"node %d is not member of channel %s\", authReq.ToId, authReq.Channel)\n\t}\n\n\tequal, err := CompareCertPublicKeys(toIdentity, s.NodeIdentity)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to compare cert public keys\")\n\t}\n\tif !equal {\n\t\ts.Logger.Debugf(\"node id mismatch for node %d, toIdentity: %s, s.NodeIdentity: %s\", authReq.FromId, string(toIdentity), string(s.NodeIdentity))\n\t\treturn nil, errors.Errorf(\"node id mismatch\")\n\t}\n\n\terr = VerifySignature(fromIdentity, SHA256Digest(msg), authReq.Signature)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"signature mismatch\")\n\t}\n\n\treturn authReq, nil\n}\n\nfunc (s *ClusterService) handleMessage(stream ClusterStepStream, addr string, exp *certificateExpirationCheck, channel string, sender uint64, streamID uint64) error {\n\trequest, err := stream.Recv()\n\tif err == io.EOF {\n\t\treturn err\n\t}\n\tif err != nil {\n\t\ts.Logger.Warningf(\"Stream read from %s failed: %v\", addr, err)\n\t\treturn err\n\t}\n\tif request == nil {\n\t\treturn errors.Errorf(\"request message is nil\")\n\t}\n","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/clusterservice.go#L159-L195","documentation":"VerifyAuthRequest verifies that the incoming request payload was actually signed by the claimed sender. It computes SHA256Digest(msg) over the request bytes and calls VerifySignature with the sender's identity (fromIdentity) and authReq.Signature. If signature verification fails, the request may have been tampered with, the payload/signature got out of sync, or the signature was produced with a key that doesn't match fromIdentity.","triggerScenarios":"ClusterService.Step receives a SignedRequest whose Signature field does not verify against the SHA-256 digest of its payload using the sender's enrolled client certificate — e.g. a client (or another orderer) signs with a different/stale key, the payload was modified after signing, or a proxy re-encoded the message bytes so the digest no longer matches.","commonSituations":"A replicated state issue where an orderer was re-enrolled (new key) but peers/services cache the old certificate; a manual or buggy client constructs Submit/Step requests without signing the exact serialized bytes; middleware (LB, service mesh) alters request bodies; Fabric binaries at mixed versions where request serialization differs.","solutions":["Re-enroll/restart the sending node so its signing key matches the certificate distributed in the channel/MSP configuration.","On the sender, confirm the request is signed over the exact serialized payload (SHA-256 digest) as received — regenerate the signature rather than reusing cached ones.","Remove any intermediaries that modify bodies (disable LB/mesh body rewriting) between the two orderers.","Ensure all Fabric orderer binaries are the same version so serialization and auth request formats agree.","Compare the sender's certificate on disk with the one in the channel's MSP and update the MSP config if the cert was rotated."],"exampleFix":"// before (sender caches signature from an older payload)\nreq.Signature = cachedSig\nreq.Payload = newPayload\n// after — always sign the exact bytes sent\nmsg := payloadBytes\ndigest := sha256.Sum256(msg)\nreq.Payload = msg\nreq.Signature = signer.Sign(digest[:])","handlingStrategy":"validation","validationCode":"// Sender-side pre-flight: sign exactly the bytes being sent\ndigest := sha256.Sum256(payload)\nsig, err := signer.Sign(digest[:])\nif err != nil { return err }\n// verify locally before sending\nif err := VerifySignature(localIdentity, digest[:], sig); err != nil {\n    return fmt.Errorf(\"local signature would fail remote verification: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := stepClient.Send(signedRequest)\nif err != nil && strings.Contains(err.Error(), \"signature mismatch\") {\n    // re-sign with the current signer and retry once\n    signedRequest.Signature = resign(signedRequest.Payload)\n    err = stepClient.Send(signedRequest)\n}","preventionTips":["Never reuse cached signatures across different payloads","Re-enroll signing identities before distributing new certificates","Keep Fabric binaries at the same version across the ordering service","Avoid proxies that rewrite gRPC message bodies"],"tags":["hyperledger-fabric","orderer","signature","authentication","security"],"backgroundTag":"signature-verification-failed","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"}