jwtk/jjwt · error · io.jsonwebtoken.JwtException
Invalid ECDSA signature format
Error message
Invalid ECDSA signature format
What it means
JJWT's transcodeDERToConcat converts an ASN.1/DER ECDSA signature into the RFC 7518 R||S concatenation. The very first structural check requires the DER blob to be at least 8 bytes and to start with the SEQUENCE tag byte 0x30. A signature failing this basic shape check causes a JwtException('Invalid ECDSA signature format').
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java:253
}
}
});
}
/**
* Transcodes the JCA ASN.1/DER-encoded signature into the concatenated
* R + S format expected by ECDSA JWS.
*
* @param derSignature The ASN1./DER-encoded. Must not be {@code null}.
* @param outputLength The expected length of the ECDSA JWS signature.
* @return The ECDSA JWS encoded signature.
* @throws JwtException If the ASN.1/DER signature format is invalid.
* @author Martin Treurnicht via <a href="https://github.com/jwtk/jjwt/commit/61510dfca58dd40b4b32c708935126785dcff48c">61510dfca58dd40b4b32c708935126785dcff48c</a>
*/
public static byte[] transcodeDERToConcat(final byte[] derSignature, int outputLength) throws JwtException {
if (derSignature.length < 8 || derSignature[0] != 48) {
throw new JwtException("Invalid ECDSA signature format");
}
int offset;
if (derSignature[1] > 0) {
offset = 2;
} else if (derSignature[1] == (byte) 0x81) {
offset = 3;
} else {
throw new JwtException("Invalid ECDSA signature format");
}
byte rLength = derSignature[offset + 1];
int i = rLength;
while ((i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0)) {
i--;
}
View on GitHub (pinned to fb71496164)
Solutions
- Confirm the input to transcodeDERToConcat is genuinely DER (starts with 0x30); raw JWS concat signatures must NOT be passed here
- Check the signature's decoded length against the expected 64/96/132 bytes before transcoding — short arrays indicate truncation upstream
- Regenerate the token from the trusted signer if the bytes are corrupted
Example fix
// before
byte[] raw = Base64.getUrlDecoder().decode(jwtSignatureSegment); // already R||S concat
byte[] der = EcSignatureAlgorithm.transcodeDERToConcat(raw, 64); // throws: not DER
// after
byte[] raw = Base64.getUrlDecoder().decode(jwtSignatureSegment);
if (raw.length != 64) throw new IllegalArgumentException("bad ES256 signature length");
// raw is already concat format; no transcoding needed Defensive patterns
Strategy: validation
Validate before calling
boolean looksLikeDer(byte[] sig) {
return sig != null && sig.length >= 8 && sig[0] == 0x30;
} Try / catch
try {
byte[] concat = EcSignatureAlgorithm.transcodeDERToConcat(derSig, 64);
} catch (JwtException e) {
throw new IllegalArgumentException("Input is not a DER ECDSA signature (expected 0x30-leading ASN.1)", e);
} Prevention
- Only call transcodeDERToConcat on signatures you know are DER-encoded
- Check sig[0] == 0x30 and length >= 8 before transcoding
- Keep a clear boundary: JWS tokens use concat signatures; only external DER input needs transcoding
When it happens
Trigger: Calling apply()/verify with a signature byte array shorter than 8 bytes or not beginning with 0x30 — i.e. not DER at all — for example a raw concat signature fed into a DER-parsing path, or random garbage/truncated bytes.
Common situations: Base64url-decoding the JWT signature segment and re-checking it manually with transcodeDERToConcat when it is already concat format; truncated storage of signature bytes; verifying tokens signed by non-JWS schemes.
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
- Provided signature is ${actual} but ${id} signatures must be
- The provided Elliptic Curve ${keyType} key size (aka order b
- Unable to verify Elliptic Curve signature using provided ECP
- Invalid ECDSA signature format.
- Unexpected unsecured Claims JWT.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/972ee71febd704bd.
Report an issue: GitHub.