gchq/CyberChef · error · OperationError

Not a known handshake message.

Error message

Not a known handshake message.

What it means

Thrown by the internal parseHandshake() in TLS.mjs when the handshake type byte is neither 0x01 (ClientHello) nor 0x02 (ServerHello). This parser only understands the two hello messages; any other handshake type (Certificate 0x0B, ServerKeyExchange 0x0C, etc.) is rejected in the switch default.

Source

Thrown at src/core/lib/TLS.mjs:100

        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;
}

/**
 * Parse a TLS Client Hello
 * @param {Stream} s
 * @param {Stream} b
 * @param {Object} h
 * @returns {JSON}
 */
function parseClientHello(s, b, h) {
    // Hello version
    h.helloVersion = {
        description: "Client Hello Version",
        length: 2,
        data: b.getBytes(2),

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Only pass ClientHello (type 0x01) or ServerHello (type 0x02) handshake messages to this parser.
  2. If you need other handshake types, this parser does not implement them — use a complete TLS dissector.
  3. Double-check that the bytes handed to parseTLSRecord start exactly at a handshake record header so the type byte is read from offset 5.

Example fix

// before: passing a Certificate handshake record
parseTLSRecord(certRecordBytes); // type byte 0x0B
// after: filter for hello messages first
if (recordBytes[5] === 0x01 || recordBytes[5] === 0x02) {
    parseTLSRecord(recordBytes);
}
Defensive patterns

Strategy: validation

Validate before calling

function isHelloHandshake(recordBytes) {
    // handshake type byte sits at offset 5 (after the 5-byte TLS record header)
    return recordBytes.length >= 6 &&
        recordBytes[5] === 0x01 || recordBytes[5] === 0x02;
}
if (!isHelloHandshake(bytes)) {
    throw new Error(
        `parseTLSRecord only decodes ClientHello (0x01) / ServerHello (0x02). ` +
        `Got handshake type 0x${(bytes[5] ?? 0).toString(16)}.`
    );
}
const r = parseTLSRecord(bytes);

Type guard

function isHelloHandshake(recordBytes) {
    return recordBytes.length >= 6 &&
        (recordBytes[5] === 0x01 || recordBytes[5] === 0x02);
}

Try / catch

try {
    record = parseTLSRecord(bytes);
} catch (e) {
    if (e instanceof OperationError && /Not a known handshake message/.test(e.message)) {
        // skip Certificate/KeyExchange/etc. — this parser only does hellos
        continue;
    }
    throw e;
}

Prevention

When it happens

Trigger: Feeding a TLS handshake record whose body is a Certificate, ServerKeyExchange, ServerHelloDone, Finished, or any non-hello message. Also reached when the byte offset is wrong (the type byte is read from the wrong position) or when the record is a hello fragment whose first body byte was misinterpreted.

Common situations: Capturing a full handshake and passing each record to this parser without filtering by handshake type; using the parser to inspect a renegotiation or post-handshake message; misaligned parsing due to a previous length error masking the real type byte.

Understand the failure class

Related errors


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