gchq/CyberChef · error · OperationError

Not a Server Hello.

Error message

Not a Server Hello.

What it means

JA3SFingerprint reads the handshake type byte and requires 2 (ServerHello). A ClientHello (type 1) or any other handshake type throws. readInt returning undefined on short input also satisfies the !== check.

Source

Thrown at src/core/operations/JA3SFingerprint.mjs:77

        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 ID
        const sessionIDLength = s.readInt(1);
        s.moveForwardsBy(sessionIDLength);

        // Cipher suite
        const cipherSuite = s.readInt(2);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. For a ClientHello, use JA3 Fingerprint, not JA3S.
  2. Confirm the record is a ServerHello (type byte === 2).
  3. Re-slice so parsing starts at the record content-type byte.
  4. Match inputFormat to the real data.

Example fix

// before
ja3s.run(clientHelloRecord, ['Hex','Base64']); // type byte 1 -> Not a Server Hello.
// after
ja3.run(clientHelloRecord, ['Hex','Base64']); // use the Client Hello op
Defensive patterns

Strategy: validation

Validate before calling

import Utils from "src/core/Utils.mjs";
function assertServerHello(input, inputFormat) {
  const b = Utils.convertToByteArray(input, inputFormat);
  if (b.length < 6) throw new Error('record too short');
  if (b[5] !== 2) {
    throw new Error(`Handshake type ${b[5]} is not ServerHello (2). For ClientHello use JA3.`);
  }
  return b;
}

Type guard

function isServerHello(bytes) {
  return bytes.length >= 6 && bytes[0] === 0x16 && bytes[5] === 2;
}

Prevention

When it happens

Trigger: The record is a ClientHello or another handshake message rather than a ServerHello; you fed JA3S a client-side capture. Also when inputFormat mismatch makes the type byte garbage or slicing is off by one.

Common situations: Using JA3S (server) on a client capture instead of JA3; off-by-one slicing; inputFormat mismatch; feeding a Certificate/ClientHello record.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/d4431c3a0f11320b. Report an issue: GitHub.