{"record":{"id":"1b92668556aa3905","repo":"gchq/CyberChef","slug":"not-enough-data-in-handshake-message","errorCode":null,"errorMessage":"Not enough data in Handshake message.","messagePattern":"Not enough data in Handshake message\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/TLS.mjs","lineNumber":87,"sourceCode":"    const h = {};\n\n    // Handshake type\n    h.handshakeType = {\n        description: \"Handshake Type\",\n        length: 1,\n        data: b.getBytes(1),\n        value: s.readInt(1)\n    };\n\n    // Handshake length\n    h.handshakeLength = {\n        description: \"Handshake Length\",\n        length: 3,\n        data: b.getBytes(3),\n        value: s.readInt(3)\n    };\n    if (s.length !== h.handshakeLength.value + 4)\n        throw new OperationError(\"Not enough data in Handshake message.\");\n\n\n    switch (h.handshakeType.value) {\n        case 0x01:\n            h.handshakeType.description = \"Client Hello\";\n            parseClientHello(s, b, h);\n            break;\n        case 0x02:\n            h.handshakeType.description = \"Server Hello\";\n            parseServerHello(s, b, h);\n            break;\n        default:\n            throw new OperationError(\"Not a known handshake message.\");\n    }\n\n    return h;\n}\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/TLS.mjs#L69-L105","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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."],"exampleFix":"// before: passing an entire record body that holds 2 handshake messages\nparseTLSRecord(recBytes); // inner parseHandshake sees wrong length\n// after: slice to one handshake message\nconst hsLen = (body[1] << 16) | (body[2] << 8) | body[3];\nparseHandshake(body.slice(0, 4 + hsLen));","handlingStrategy":"validation","validationCode":"function sliceOneHandshake(body) {\n    if (body.length < 4) throw new Error(\"Handshake body too short for a header\");\n    const len = (body[1] << 16) | (body[2] << 8) | body[3]; // 3-byte big-endian\n    if (body.length !== 4 + len) {\n        throw new Error(\n            `Handshake length mismatch: declared ${len} but body has ${body.length - 4} bytes. ` +\n            `The message may be fragmented across records.`\n        );\n    }\n    return body.slice(0, 4 + len);\n}","typeGuard":"function isExactlyOneHandshake(body) {\n    return body.length >= 4 &&\n        body.length === 4 + ((body[1] << 16) | (body[2] << 8) | body[3]);\n}","tryCatchPattern":"try {\n    record = parseTLSRecord(buf);\n} catch (e) {\n    if (e instanceof OperationError && /Not enough data in Handshake/.test(e.message)) {\n        // handshake message is fragmented across records; buffer more and retry\n        return await reassembleAndRetry();\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["tls","parsing","handshake","framing","length-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}