{"record":{"id":"d93a35b7f4b8f3a9","repo":"gchq/CyberChef","slug":"incorrect-handshake-length-d93a35","errorCode":null,"errorMessage":"Incorrect handshake length.","messagePattern":"Incorrect handshake length\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/JA3Fingerprint.mjs","lineNumber":72,"sourceCode":"     * @returns {string}\n     */\n    run(input, args) {\n        const [inputFormat, outputFormat] = args;\n\n        input = Utils.convertToByteArray(input, inputFormat);\n        const s = new Stream(new Uint8Array(input));\n\n        const handshake = s.readInt(1);\n        if (handshake !== 0x16)\n            throw new OperationError(\"Not handshake data.\");\n\n        // Version\n        s.moveForwardsBy(2);\n\n        // Length\n        const length = s.readInt(2);\n        if (s.length !== length + 5)\n            throw new OperationError(\"Incorrect handshake length.\");\n\n        // Handshake type\n        const handshakeType = s.readInt(1);\n        if (handshakeType !== 1)\n            throw new OperationError(\"Not a Client Hello.\");\n\n        // Handshake length\n        const handshakeLength = s.readInt(3);\n        if (s.length !== handshakeLength + 9)\n            throw new OperationError(\"Not enough data in Client Hello.\");\n\n        // Hello version\n        const helloVersion = s.readInt(2);\n\n        // Random\n        s.moveForwardsBy(32);\n\n        // Session ID","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/JA3Fingerprint.mjs#L54-L90","documentation":"After skipping version (2 bytes), JA3Fingerprint reads the 2-byte record length and requires the total stream length to equal length + 5 (5 = content type + version + length fields). A mismatch means trailing bytes (multiple records concatenated) or a truncated record. Note readInt returns undefined on exhaustion, so short input also satisfies the !== condition and throws this message.","triggerScenarios":"Multiple TLS records concatenated in the input (length+5 < total), a truncated record (length+5 > total), or wrong inputFormat making the length field garbage. Feeding only part of the record also triggers it.","commonSituations":"Pasted the full handshake (ClientHello + ServerHello + more) instead of one record; truncated paste; inputFormat mismatch corrupting the length field.","solutions":["Feed exactly one TLS record: trim trailing bytes so total === length+5.","Confirm the input is not truncated (the declared length fits in the buffer).","Match inputFormat to the real data so the length field parses correctly.","Split multi-record captures into individual records before this op."],"exampleFix":"// before\nja3.run(fullStream, ['Hex','Base64']); // length+5 < total -> Incorrect handshake length.\n// after\nconst recLen = (bytes[3]<<8)|bytes[4];\nconst oneRecord = bytes.slice(0, recLen + 5);\nja3.run(oneRecord, ['Hex','Base64']);","handlingStrategy":"validation","validationCode":"import Utils from \"src/core/Utils.mjs\";\nfunction assertSingleRecord(input, inputFormat) {\n  const b = Utils.convertToByteArray(input, inputFormat);\n  if (b.length < 5) throw new Error('record too short');\n  const recLen = (b[3] << 8) | b[4];\n  if (b.length !== recLen + 5) {\n    throw new Error(`Stream length ${b.length} != record length ${recLen}+5. Feed exactly one TLS record.`);\n  }\n  return b;\n}","typeGuard":"function isSingleTlsRecord(bytes) {\n  if (bytes.length < 5) return false;\n  const recLen = (bytes[3] << 8) | bytes[4];\n  return bytes.length === recLen + 5;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["tls","network","parsing","cyberchef","input-validation","ja3"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}