networking · intermediate · ~15 min · safe pentest lab

Extract the SNI host from a TLS extension

Bounds-safe parsing of a length-prefixed TLS field.

Challenge

Pull the server hostname (SNI) out of a TLS extension payload — the plaintext field every passive TLS monitor reads from a ClientHello. Bounds-safe parsing is the point.

Task

Implement int extract_sni(const uint8_t *ext, size_t n, char *out, size_t cap). The grader passes a static byte array; no TLS connections are made.

Input

  • ext: the SNI extension payload, laid out as [list_len:2][name_type:1][name_len:2][host...], with all length fields big-endian.
  • n: number of bytes available in ext.
  • out: buffer to receive the hostname.
  • cap: capacity of out in bytes.

Output

Copy the host bytes into out, NUL-terminated, and return the host length. Return -1 on NULL input, n < 5, a name_type other than 0x00 (host_name), a declared length that runs past n, or if the host plus NUL would overflow cap.

Example

{0x00,0x0E,0x00,0x00,0x0B,'e','x','a','m','p','l','e','.','c','o','m'}  ->  11, out = "example.com"
{0x00,0x06,0x01,0x00,0x03,'a','b','c'}   -> -1   (name_type 0x01, not host_name)
{0x00,0x10,0x00,0x00,0x20,'a','b'}       -> -1   (name_len runs past n)
out cap = 4 with an 11-byte host          -> -1   (output overflow)
NULL ext, or n = 2                        -> -1

Edge cases

  • name_type must be 0x00; anything else returns -1.
  • A name_len that would read past n, or write past cap (including the NUL), returns -1.

Why this matters

The SNI extension carries the hostname in plaintext in a ClientHello — the field every passive TLS monitor reads. Parsing it safely is the lesson.

Input format

ext, the SNI extension payload [list_len:2][name_type:1][name_len:2][host...] (big-endian lengths); n, bytes available; out buffer; cap, its size.

Output format

Host length with out filled (NUL-terminated) on success; -1 on NULL, short input, wrong type, length past n, or output overflow.

Constraints

All length fields are big-endian; validate every length against n and cap before copying.

Starter code

#include <stdint.h>
#include <stddef.h>
int extract_sni(const uint8_t *ext, size_t n, char *out, size_t cap) {
    /* TODO */
    (void)ext; (void)n; (void)out; (void)cap;
    return -1;
}

Common mistakes

Reading lengths little-endian. Skipping the type check. Forgetting the NUL terminator's byte in the capacity check.

Edge cases to handle

Non-host type. Truncated host. Tiny output buffer.

Complexity

O(name_len).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.