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
- Verify the raw $points string is exactly 2x the curve's coordinate length in bytes before calling toAsn1
- Ensure you are using the same curve for signing and for ASN.1 conversion
- Confirm the input is raw binary, not hex or base64 encoded
- 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
- Always carry signatures as raw binary; decode base64 once, exactly
- Pin the curve and compute lengths from it, never hardcode per call site
- Add a length assertion before ASN.1 conversion
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
- Invalid data. Should start with a sequence.
- Invalid data. Should contain an integer.
- Error while encoding to JSON
- The type of the provided key is not
- The length of the provided key is different than
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)