gchq/CyberChef · error · OperationError
Incorrect handshake length.
Error message
Incorrect handshake length.
What it means
After skipping version (2 bytes), JA3SFingerprint reads the 2-byte record length and requires total stream length === length + 5. A mismatch means trailing bytes (concatenated records) or a truncated record; readInt returning undefined on short input also satisfies the !== check.
Source
Thrown at src/core/operations/JA3SFingerprint.mjs:72
* @returns {string}
*/
run(input, args) {
const [inputFormat, outputFormat] = args;
input = Utils.convertToByteArray(input, inputFormat);
const s = new Stream(new Uint8Array(input));
const handshake = s.readInt(1);
if (handshake !== 0x16)
throw new OperationError("Not handshake data.");
// Version
s.moveForwardsBy(2);
// Length
const length = s.readInt(2);
if (s.length !== length + 5)
throw new OperationError("Incorrect handshake length.");
// Handshake type
const handshakeType = s.readInt(1);
if (handshakeType !== 2)
throw new OperationError("Not a Server Hello.");
// Handshake length
const handshakeLength = s.readInt(3);
if (s.length !== handshakeLength + 9)
throw new OperationError("Not enough data in Server Hello.");
// Hello version
const helloVersion = s.readInt(2);
// Random
s.moveForwardsBy(32);
// Session IDView on GitHub (pinned to 4290ea7539)
Solutions
- Feed exactly one record: trim so total === length+5.
- Confirm the record is not truncated.
- Match inputFormat so the length field parses correctly.
- Split multi-record captures into individual records.
Example fix
// before ja3s.run(fullServerStream, ['Hex','Base64']); // length+5 < total -> Incorrect handshake length. // after const recLen = (bytes[3]<<8)|bytes[4]; const oneRecord = bytes.slice(0, recLen + 5); ja3s.run(oneRecord, ['Hex','Base64']);
Defensive patterns
Strategy: validation
Validate before calling
import Utils from "src/core/Utils.mjs";
function assertSingleRecord(input, inputFormat) {
const b = Utils.convertToByteArray(input, inputFormat);
if (b.length < 5) throw new Error('record too short');
const recLen = (b[3] << 8) | b[4];
if (b.length !== recLen + 5) {
throw new Error(`Stream length ${b.length} != record length ${recLen}+5. Feed exactly one TLS record.`);
}
return b;
} Type guard
function isSingleTlsRecord(bytes) {
if (bytes.length < 5) return false;
const recLen = (bytes[3] << 8) | bytes[4];
return bytes.length === recLen + 5;
} Prevention
- Feed exactly one TLS record (trim trailing bytes).
- Confirm the input is not truncated.
- Match inputFormat so the length field parses correctly.
- Split multi-record captures before this op.
When it happens
Trigger: Multiple TLS records concatenated (length+5 < total), a truncated ServerHello record (length+5 > total), or inputFormat mismatch corrupting the length field.
Common situations: Pasting the whole server-side handshake (ServerHello + Certificate + ServerKeyExchange) instead of one record; truncated paste; inputFormat mismatch.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Not handshake data.
- Not a Server Hello.
- Not enough data in Server Hello.
- Not handshake data.
- Incorrect handshake length.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/ae7936022b554eae.
Report an issue: GitHub.