hyperledger/fabric · error

failed unmarshaling certificate

Error message

failed unmarshaling certificate

What it means

When a certificate has a high-S ECDSA signature, the sanitizer re-encodes the whole certificate with the normalized low-S signature. It does this by ASN.1-unmarshaling cert.Raw into a local certificate struct; if that fails, 'failed unmarshaling certificate' is wrapped and returned.

Source

Thrown at common/crypto/sanitize.go:70

	r, s, err := utils.UnmarshalECDSASignature(cert.Signature)
	if err != nil {
		return nil, errors.Wrapf(err, "failed unmarshaling ECDSA signature on identity: %s", string(initialPEM))
	}

	// We assume that the consenter and the CA use the same signature scheme.
	curveOrderUsedByCryptoGen := cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().N
	halfOrder := new(big.Int).Rsh(curveOrderUsedByCryptoGen, 1)
	// Low S, nothing to do here!
	if s.Cmp(halfOrder) != 1 {
		return initialPEM, nil
	}
	// Else it's high-S, so shift it below half the order.
	s.Sub(curveOrderUsedByCryptoGen, s)

	var newCert certificate
	_, err = asn1.Unmarshal(cert.Raw, &newCert)
	if err != nil {
		return nil, errors.Wrapf(err, "failed unmarshaling certificate")
	}

	newSig, err := utils.MarshalECDSASignature(r, s)
	if err != nil {
		return nil, errors.Wrapf(err, "failed marshaling ECDSA signature")
	}
	newCert.SignatureValue = asn1.BitString{Bytes: newSig, BitLength: len(newSig) * 8}

	newCert.Raw = nil
	newRaw, err := asn1.Marshal(newCert)
	if err != nil {
		return nil, errors.Wrapf(err, "failed marshaling new certificate")
	}

	finalPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: newRaw})
	return finalPEM, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Re-issue the certificate so the CA signs it with low-S directly (fix CA's RFC6979/low-S configuration)
  2. Compare the failing cert's DER with openssl asn1parse to find the non-standard encoding
  3. Convert the cert to canonical DER before use (re-encode via Go's x509 or openssl)
  4. Upgrade the fabric version, as asn1 handling of exotic encodings has improved over releases
Defensive patterns

Strategy: try-catch

Validate before calling

func hasHighS(cert *x509.Certificate) (bool, error) {
    r, s, err := utils.UnmarshalECDSASignature(cert.Signature)
    if err != nil { return false, err }
    half := new(big.Int).Rsh(cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().N, 1)
    return s.Cmp(half) == 1, nil
}

Try / catch

out, err := crypto.SanitizeX509Cert(certPEM)
if err != nil && strings.Contains(err.Error(), "failed unmarshaling certificate") {
    // cert is high-S and non-canonical DER; re-issue from CA
}

Prevention

When it happens

Trigger: A high-S certificate whose raw DER cannot be re-parsed by encoding/asn1 into the sanitizer's certificate struct — e.g. non-standard extensions/encodings that break strict ASN.1 parsing.

Common situations: Certificates from CAs emitting non-canonical DER (e.g. weird OPTIONAL fields, zero-length encodings); intermediate tooling re-encoding certificates non-strictly; very old/uncommon CA software.

Understand the failure class

Related errors


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