# TLS 1.3 Handshake in ~200 Lines of C

From-scratch TLS 1.3 handshake implementation. No OpenSSL, no third-party libraries — just POSIX sockets and hand-written cryptography.

**⚠️ Educational code only. NOT for production use.**

No certificate verification, no side-channel protection, minimal error handling.

## What's Implemented

- **Cipher suite**: `TLS_AES_128_GCM_SHA256` (0x1301)
- **Key exchange**: X25519 (Curve25519 ECDHE)
- **Key schedule**: HKDF-SHA256 with TLS 1.3 `Derive-Secret` / `HKDF-Expand-Label`
- **AEAD**: AES-128-GCM (CTR + GHASH)
- **Full 1-RTT handshake**: ClientHello → ServerHello → {EncryptedExtensions, Certificate, CertificateVerify, Finished} → [Finished]
- **Application data**: Encrypted HTTP GET after handshake

## Files

| File | Lines | Description |
|------|-------|-------------|
| `tls13.c` | ~460 | Handshake protocol (~200 lines of core logic + record layer + main) |
| `sha256.c/h` | ~150 | SHA-256 hash (RFC 6234) |
| `x25519.c/h` | ~310 | X25519 Diffie-Hellman (RFC 7748), 5×51-bit Montgomery ladder |
| `hkdf.c/h` | ~190 | HMAC-SHA256 + HKDF + TLS 1.3 Derive-Secret/Expand-Label |
| `aes_gcm.c/h` | ~370 | AES-128 core + GCM mode (NIST SP 800-38D) |
| `test_crypto.c` | ~220 | RFC test vector validation |

## Build & Run

```bash
make           # build tls13 binary
make test      # run RFC test vector suite (14 tests)
```

### Test against a local OpenSSL server

```bash
# Terminal 1: start TLS 1.3 server
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
    -keyout /tmp/key.pem -out /tmp/cert.pem -days 1 -nodes -subj "/CN=localhost"
openssl s_server -accept 14433 -cert /tmp/cert.pem -key /tmp/key.pem \
    -tls1_3 -ciphersuites TLS_AES_128_GCM_SHA256 -www

# Terminal 2: run handshake
./tls13 localhost 14433
```

Expected output:

```
[+] TCP connected to localhost:14433
[+] ClientHello sent (166 bytes)
[+] ServerHello received
[+] Handshake keys derived
[+] Server Finished verified
[+] Client Finished sent
[+] Application keys derived
[+] HTTP request sent

[+] Skipped post-handshake message (type 22)
[+] Skipped post-handshake message (type 22)
HTTP/1.0 200 ok
Content-type: text/html
...
[+] TLS 1.3 handshake complete!
```

## Test Vectors

All crypto primitives are validated against official test vectors:

- **SHA-256**: NIST FIPS 180-4 ("abc", empty, 448-bit)
- **HMAC-SHA256**: RFC 4231 Test Case 2
- **X25519**: RFC 7748 §6.1 (both vectors)
- **HKDF**: RFC 5869 Appendix A Test Case 1
- **AES-128**: FIPS 197 Appendix B
- **AES-128-GCM**: NIST SP 800-38D Test Case 3 (encrypt + decrypt + tamper rejection)

## Not Implemented

- Certificate chain verification
- 0-RTT (Early Data)
- PSK / session resumption
- HelloRetryRequest
- Multiple cipher suites
- Client certificates
- Production-grade error handling
- Side-channel protections (constant-time code)

## References

- [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) — TLS 1.3
- [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748) — X25519
- [RFC 5869](https://www.rfc-editor.org/rfc/rfc5869) — HKDF
- [NIST SP 800-38D](https://csrc.nist.gov/publications/detail/sp/800-38d/final) — AES-GCM
- [RFC 8448](https://www.rfc-editor.org/rfc/rfc8448) — Example Handshake Traces
