networking · intermediate · ~15 min · safe pentest lab
Bounds-safe parsing of a length-prefixed TLS field.
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.
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.
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.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.
{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
name_type must be 0x00; anything else returns -1.name_len that would read past n, or write past cap (including the NUL), returns -1.The SNI extension carries the hostname in plaintext in a ClientHello — the field every passive TLS monitor reads. Parsing it safely is the lesson.
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.
Host length with out filled (NUL-terminated) on success; -1 on NULL, short input, wrong type, length past n, or output overflow.
All length fields are big-endian; validate every length against n and cap before copying.
#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;
}
Reading lengths little-endian. Skipping the type check. Forgetting the NUL terminator's byte in the capacity check.
Non-host type. Truncated host. Tiny output buffer.
O(name_len).
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.