gchq/CyberChef · error · OperationError
Not enough data in Handshake message.
Error message
Not enough data in Handshake message.
What it means
Thrown by the internal parseHandshake() in TLS.mjs when the declared handshake length (3-byte field after the handshake type) plus the 4-byte handshake header does not equal the bytes available in the handshake body. This guards the inner handshake message framing: the parser needs exactly the declared number of bytes to read the Client/Server Hello fields that follow.
Source
Thrown at src/core/lib/TLS.mjs:87
const h = {};
// Handshake type
h.handshakeType = {
description: "Handshake Type",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
// Handshake length
h.handshakeLength = {
description: "Handshake Length",
length: 3,
data: b.getBytes(3),
value: s.readInt(3)
};
if (s.length !== h.handshakeLength.value + 4)
throw new OperationError("Not enough data in Handshake message.");
switch (h.handshakeType.value) {
case 0x01:
h.handshakeType.description = "Client Hello";
parseClientHello(s, b, h);
break;
case 0x02:
h.handshakeType.description = "Server Hello";
parseServerHello(s, b, h);
break;
default:
throw new OperationError("Not a known handshake message.");
}
return h;
}
View on GitHub (pinned to 4290ea7539)
Solutions
- Reassemble fragmented handshake messages across records before parsing: TLS allows one handshake message to span multiple records, so buffer until you have 4 + declared-length bytes.
- Confirm the 3-byte handshake length is read big-endian and unsigned.
- If multiple handshake messages are concatenated in one record, parse them iteratively using the handshake length field rather than passing the whole record body.
Example fix
// before: passing an entire record body that holds 2 handshake messages parseTLSRecord(recBytes); // inner parseHandshake sees wrong length // after: slice to one handshake message const hsLen = (body[1] << 16) | (body[2] << 8) | body[3]; parseHandshake(body.slice(0, 4 + hsLen));
Defensive patterns
Strategy: validation
Validate before calling
function sliceOneHandshake(body) {
if (body.length < 4) throw new Error("Handshake body too short for a header");
const len = (body[1] << 16) | (body[2] << 8) | body[3]; // 3-byte big-endian
if (body.length !== 4 + len) {
throw new Error(
`Handshake length mismatch: declared ${len} but body has ${body.length - 4} bytes. ` +
`The message may be fragmented across records.`
);
}
return body.slice(0, 4 + len);
} Type guard
function isExactlyOneHandshake(body) {
return body.length >= 4 &&
body.length === 4 + ((body[1] << 16) | (body[2] << 8) | body[3]);
} Try / catch
try {
record = parseTLSRecord(buf);
} catch (e) {
if (e instanceof OperationError && /Not enough data in Handshake/.test(e.message)) {
// handshake message is fragmented across records; buffer more and retry
return await reassembleAndRetry();
}
throw e;
} Prevention
- TLS handshake messages can span multiple records — reassemble by the 4-byte handshake header + 3-byte length before parsing.
- If a record body holds multiple handshake messages, iterate them by length rather than parsing the whole body once.
- Read the 3-byte handshake length as big-endian unsigned.
When it happens
Trigger: The handshake record's body (passed in from parseTLSRecord) is shorter or longer than the declared handshake length. Happens when a handshake message spans multiple TLS records (fragmentation across records), when bytes are dropped, or when the 3-byte length is misread (e.g. signed read).
Common situations: A ClientHello large enough to be split across TLS records (common with long SNI/extension lists); capture that starts mid-handshake; a server that coalesces multiple handshake messages in one record (this parser expects one message per call).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Not handshake data.
- Incorrect handshake length.
- Not a known handshake message.
- Not handshake data.
- Incorrect handshake length.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/1b92668556aa3905.
Report an issue: GitHub.