lcobucci/jwt · error · Lcobucci\JWT\Signer\Ecdsa\ConversionFailed

Invalid signature length.

Error message

Invalid signature length.

What it means

Thrown by MultibyteStringConverter::toAsn1 when the concatenated ECDSA signature points (R and S) do not have exactly the expected byte length for the curve (e.g. 32 bytes for P-256, 48 for P-384). The library requires a fixed-width pair of hex-encoded points before wrapping them in an ASN.1 DER sequence; any shorter or longer input is rejected to avoid producing a malformed signature.

Solutions

  1. Verify the raw $points string is exactly 2x the curve's coordinate length in bytes before calling toAsn1
  2. Ensure you are using the same curve for signing and for ASN.1 conversion
  3. Confirm the input is raw binary, not hex or base64 encoded
  4. Regenerate the signature if it was produced with a mismatched key/curve

Example fix

// before
$asn1 = $converter->toAsn1($base64Signature, 32);
// after
$raw = base64_decode($base64Signature, true);
assert(strlen($raw) === 64);
$asn1 = $converter->toAsn1($raw, 32);
Defensive patterns

Strategy: validation

Validate before calling

if (strlen($points) !== 2 * $length) { throw new InvalidArgumentException('Signature must be ' . (2 * $length) . ' bytes'); }

Try / catch

try { $asn1 = $converter->toAsn1($points, 32); } catch (\Jose\Component\Signature\Exception\ConversionFailed $e) { /* handle bad signature length */ }

Prevention

When it happens

Trigger: Calling toAsn1() with a $points string whose octet length differs from the $length argument, typically because the raw signature was produced on a different curve or the binary signature was re-encoded (e.g. hex/base64 round trip mishandled, leading zero bytes stripped or padding added).

Common situations: Migrating between curve sizes (P-256 vs P-384), decoding a signature with base64_decode returning padded/corrupted data, or passing a hex string instead of raw binary bytes.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/a2b9a26ccb8e9f84. Report an issue: GitHub.

Appendix: source

Thrown at src/Signer/Ecdsa/MultibyteStringConverter.php:49

 *
 * @internal
 */
final readonly class MultibyteStringConverter implements SignatureConverter
{
    private const string ASN1_SEQUENCE          = '30';
    private const string ASN1_INTEGER           = '02';
    private const int ASN1_MAX_SINGLE_BYTE      = 128;
    private const string ASN1_LENGTH_2BYTES     = '81';
    private const string ASN1_BIG_INTEGER_LIMIT = '7f';
    private const string ASN1_NEGATIVE_INTEGER  = '00';
    private const int BYTE_SIZE                 = 2;

    public function toAsn1(string $points, int $length): string
    {
        $points = bin2hex($points);

        if (self::octetLength($points) !== $length) {
            throw ConversionFailed::invalidLength();
        }

        $pointR = self::preparePositiveInteger(substr($points, 0, $length));
        $pointS = self::preparePositiveInteger(substr($points, $length, null));

        $lengthR = self::octetLength($pointR);
        $lengthS = self::octetLength($pointS);

        $totalLength  = $lengthR + $lengthS + self::BYTE_SIZE + self::BYTE_SIZE;
        $lengthPrefix = $totalLength > self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';

        $asn1 = hex2bin(
            self::ASN1_SEQUENCE
            . $lengthPrefix . dechex($totalLength)
            . self::ASN1_INTEGER . dechex($lengthR) . $pointR
            . self::ASN1_INTEGER . dechex($lengthS) . $pointS,
        );
        assert(is_string($asn1));

View on GitHub (pinned to 375813049c)