{"record":{"id":"9b69019ddaabbd8d","repo":"hyperledger/fabric","slug":"failed-unmarshaling-ecdsa-signature-on-identity","errorCode":null,"errorMessage":"failed unmarshaling ECDSA signature on identity: %s","messagePattern":"failed unmarshaling ECDSA signature on identity: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/crypto/sanitize.go","lineNumber":54,"sourceCode":"\tsID.IdBytes = finalPEM\n\n\treturn proto.Marshal(sID)\n}\n\n// SanitizeX509Cert sanitizes an X.509 certificate to ensure that the ECDSA signature uses a \"low-S\" value.\nfunc SanitizeX509Cert(initialPEM []byte) ([]byte, error) {\n\tder, _ := pem.Decode(initialPEM)\n\tif der == nil {\n\t\treturn nil, errors.Errorf(\"failed to PEM decode identity bytes: %s\", string(initialPEM))\n\t}\n\tcert, err := x509.ParseCertificate(der.Bytes)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed parsing certificate %s\", string(initialPEM))\n\t}\n\n\tr, s, err := utils.UnmarshalECDSASignature(cert.Signature)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed unmarshaling ECDSA signature on identity: %s\", string(initialPEM))\n\t}\n\n\t// We assume that the consenter and the CA use the same signature scheme.\n\tcurveOrderUsedByCryptoGen := cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().N\n\thalfOrder := new(big.Int).Rsh(curveOrderUsedByCryptoGen, 1)\n\t// Low S, nothing to do here!\n\tif s.Cmp(halfOrder) != 1 {\n\t\treturn initialPEM, nil\n\t}\n\t// Else it's high-S, so shift it below half the order.\n\ts.Sub(curveOrderUsedByCryptoGen, s)\n\n\tvar newCert certificate\n\t_, err = asn1.Unmarshal(cert.Raw, &newCert)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed unmarshaling certificate\")\n\t}\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/crypto/sanitize.go#L36-L72","documentation":"SanitizeX509Cert extracts the certificate's ECDSA signature and unmarshals the r,s integers. If cert.Signature is not a valid ASN.1 ECDSA signature pair, this wrapped error is returned. The sanitizer normalizes high-S signatures, so it must be able to parse the signature first.","triggerScenarios":"Sanitizing a certificate whose signature is not ECDSA (e.g. RSA or Ed25519 certs), or whose signature bytes are corrupted/non-standard ASN.1.","commonSituations":"Fabric deployment using RSA certificates where the sanitizer assumes ECDSA; certificates issued by a non-conformant CA encoding signatures differently; corrupted cert payloads in gossip or identity messages.","solutions":["Ensure all node/CA certificates are ECDSA-signed (fabric's sanitizer assumes ECDSA keys — see the type assertion to *ecdsa.PublicKey)","Re-issue certificates from a standards-compliant CA with proper DER ECDSA signatures","Check the wrapped inner error to confirm whether the signature is malformed or of the wrong algorithm","Verify the certificate wasn't truncated/re-encoded by intermediate tooling"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"blk, _ := pem.Decode(certPEM)\ncert, err := x509.ParseCertificate(blk.Bytes)\nif err == nil {\n    if _, ok := cert.PublicKey.(*ecdsa.PublicKey); !ok {\n        return errors.New(\"certificate must be ECDSA-signed for fabric sanitization\")\n    }\n}","typeGuard":null,"tryCatchPattern":"out, err := crypto.SanitizeX509Cert(certPEM)\nif err != nil && strings.Contains(err.Error(), \"failed unmarshaling ECDSA signature\") {\n    // likely non-ECDSA cert; re-issue from CA with ECDSA\n}","preventionTips":["Issue all fabric node/identity certs with ECDSA keys and signatures","Reject non-ECDSA certs at enrollment time","Use CAs that produce standards-compliant DER signatures"],"tags":["ecdsa","signature","x509","hyperledger-fabric"],"backgroundTag":"ecdsa-signature-unmarshal-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"}