golang/go · error

invalid signature

Error message

invalid signature

What it means

Returned by the s390x (IBM Z) hardware-accelerated ECDSA verify path when a signature's R or S component byte length exceeds the KDSA instruction's blockSize for the curve (32 for P-256, 48 for P-384, 80 for P-521). Since a canonical scalar mod n always fits in blockSize bytes, an oversized component cannot be a valid signature and is rejected before the KDSA call (which would otherwise panic in appendBlock).

Source

Thrown at src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go:173

			}
			return &Signature{R: r, S: s}, nil
		case 1: // error
			return nil, errors.New("zero parameter")
		case 2: // retry
			continue
		}
	}
}

func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
	functionCode, blockSize, ok := canUseKDSA(c.curve)
	if !ok {
		return verifyGeneric(c, pub, hash, sig)
	}

	r, s := sig.R, sig.S
	if len(r) > blockSize || len(s) > blockSize {
		return errors.New("invalid signature")
	}

	// The parameter block looks like the following for verify:
	// 	+---------------------+
	// 	|   Signature(R)      |
	//	+---------------------+
	//	|   Signature(S)      |
	//	+---------------------+
	//	|   Hashed Message    |
	//	+---------------------+
	//	|   Public Key X      |
	//	+---------------------+
	//	|   Public Key Y      |
	//	+---------------------+
	//	|                     |
	//	|        ...          |
	//	|                     |
	//	+---------------------+

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure R and S are decoded and stored as fixed-width big-endian byte slices whose length matches blockSize (right-aligned, zero-padded on the left).
  2. If you control encoding, use the curve's signature-marshal helpers (e.g. SignASN1 / VerifyASN1) rather than constructing Signature{R,S} manually.
  3. On non-s390x targets this path is unreachable; reproduce on real IBM Z hardware or under qemu-s390x to debug.

Example fix

// before: r and s are raw *big.Int byte slices of arbitrary length
sig := &ecdsa.Signature{R: rawR, S: rawS}
return ecdsa.Verify(pub, hash, sig)

// after: normalize to fixed-width big-endian of blockSize
r := fixedWidth(rawR, blockSize)
s := fixedWidth(rawS, blockSize)
// where fixedWidth left-pads with zeros and errors if input exceeds blockSize
Defensive patterns

Strategy: validation

Validate before calling

// Before calling ecdsa.Verify with a manually built Signature on s390x:
bs := blockSizeForCurve(curve) // 32 / 48 / 80
if len(sig.R) > bs || len(sig.S) > bs {
    return fmt.Errorf("signature R/S exceeds curve block size %d", bs)
}
return ecdsa.Verify(pub, hash, sig)

Try / catch

// Go: check err from Verify; treat invalid-signature errors as auth failure.
if err := ecdsa.Verify(pub, hash, sig); err != nil {
    // err may be 'invalid signature' from oversized R/S or KDSA rejection
    return fmt.Errorf("signature rejected: %w", err)
}

Prevention

When it happens

Trigger: Calling ecdsa.Verify (or the internal verify) on s390x hardware where supportsKDSA is true, with a Signature whose R or S fields were assembled from malformed/un-trimmed big-endian byte slices longer than the curve's blockSize.

Common situations: Decoding an ASN.1 DER signature whose integers were not left-trimmed of zero padding into fixed-size buffers; copying a P-521 raw R/S (66 bytes) without zero-padding into an 80-byte block; interoperating with a peer that pads integers to the field size rather than the order size.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/2ce1b365890049d0. Report an issue: GitHub.