code wiki / (root) / tls13.nx

tls13.nx source

↩ module page · 188 lines · 6834 B

1// tls13.nx -- TLS 1.3 (RFC 8446) record-layer constants + framing. 2// 3// This is the skeleton of the TLS 1.3 implementation, not the full 4// state machine. Ships: 5// - ContentType + HandshakeType enum constants 6// - ExtensionType enum constants 7// - Version constants 8// - Record-layer struct definitions + byte-level parse / emit 9// 10// What it does NOT ship (follow-up): 11// - ClientHello / ServerHello / EncryptedExtensions / Finished 12// state-machine driver 13// - HKDF-based key-schedule ordering 14// - 0-RTT / session resumption 15// - Full extension parsing (SNI, ALPN, signature_algorithms, etc.) 16// 17// Pair with AEAD (chacha20-poly1305 shipped; AES-256-GCM pending) 18// + HMAC + HKDF + X25519 + Ed25519 + X.509 primitives that are all 19// already in-tree. 20// 21// References: 22// RFC 8446 (TLS 1.3) -- primary specification 23// RFC 9001 (QUIC TLS) -- alternate framing; outside this file's scope 24// RFC 9578 (X25519Kyber768Draft00) -- PQ hybrid; tls13_extension 25// constants prepared for it 26 27import "syscalls.nx" 28 29// ---- version constants ----------------------------------------- 30// 31// TLS 1.3 retains TLS 1.2's legacy_version (0x0303) in the record 32// header for backward compatibility; the real version is signalled 33// via extension 0x002B (supported_versions). 34 35const TLS_LEGACY_VERSION: i64 = 0x0303 // TLS 1.2 wire value 36const TLS_13_VERSION: i64 = 0x0304 // "real" TLS 1.3 advertised via extension 37 38// ---- ContentType (RFC 8446 §B.1) ------------------------------- 39 40const CT_INVALID: i64 = 0 41const CT_CHANGE_CIPHER_SPEC: i64 = 20 42const CT_ALERT: i64 = 21 43const CT_HANDSHAKE: i64 = 22 44const CT_APPLICATION_DATA: i64 = 23 45const CT_HEARTBEAT: i64 = 24 46 47// ---- HandshakeType (RFC 8446 §B.3) ----------------------------- 48 49const HT_CLIENT_HELLO: i64 = 1 50const HT_SERVER_HELLO: i64 = 2 51const HT_NEW_SESSION_TICKET: i64 = 4 52const HT_END_OF_EARLY_DATA: i64 = 5 53const HT_ENCRYPTED_EXTENSIONS: i64 = 8 54const HT_CERTIFICATE: i64 = 11 55const HT_CERTIFICATE_REQUEST: i64 = 13 56const HT_CERTIFICATE_VERIFY: i64 = 15 57const HT_FINISHED: i64 = 20 58const HT_KEY_UPDATE: i64 = 24 59const HT_MESSAGE_HASH: i64 = 254 60 61// ---- ExtensionType (RFC 8446 §4.2 + IANA updates) -------------- 62 63const EXT_SERVER_NAME: i64 = 0 64const EXT_MAX_FRAGMENT_LENGTH: i64 = 1 65const EXT_STATUS_REQUEST: i64 = 5 66const EXT_SUPPORTED_GROUPS: i64 = 10 67const EXT_SIGNATURE_ALGORITHMS: i64 = 13 68const EXT_USE_SRTP: i64 = 14 69const EXT_APPLICATION_LAYER_PROTOCOL: i64 = 16 // ALPN 70const EXT_SIGNED_CERTIFICATE_TIMESTAMP: i64 = 18 71const EXT_PADDING: i64 = 21 72const EXT_PRE_SHARED_KEY: i64 = 41 73const EXT_EARLY_DATA: i64 = 42 74const EXT_SUPPORTED_VERSIONS: i64 = 43 75const EXT_COOKIE: i64 = 44 76const EXT_PSK_KEY_EXCHANGE_MODES: i64 = 45 77const EXT_CERTIFICATE_AUTHORITIES: i64 = 47 78const EXT_OID_FILTERS: i64 = 48 79const EXT_POST_HANDSHAKE_AUTH: i64 = 49 80const EXT_SIGNATURE_ALGORITHMS_CERT: i64 = 50 81const EXT_KEY_SHARE: i64 = 51 82 83// ---- NamedGroup (RFC 8446 §4.2.7) ------------------------------ 84// 85// Curves available for key exchange. X25519 is the modern 86// default; Kyber768 (PQC hybrid) additions are draft / RFC 9578. 87 88const NG_SECP256R1: i64 = 23 89const NG_SECP384R1: i64 = 24 90const NG_SECP521R1: i64 = 25 91const NG_X25519: i64 = 29 92const NG_X448: i64 = 30 93// Post-quantum hybrid per RFC 9578 (draft). 94const NG_X25519_KYBER768_DRAFT00: i64 = 0x6399 95 96// ---- SignatureScheme (RFC 8446 §4.2.3) ------------------------- 97 98const SS_RSA_PKCS1_SHA256: i64 = 0x0401 99const SS_RSA_PKCS1_SHA384: i64 = 0x0501 100const SS_RSA_PKCS1_SHA512: i64 = 0x0601 101const SS_ECDSA_SECP256R1_SHA256: i64 = 0x0403 102const SS_ECDSA_SECP384R1_SHA384: i64 = 0x0503 103const SS_ED25519: i64 = 0x0807 104const SS_ED448: i64 = 0x0808 105const SS_RSA_PSS_RSAE_SHA256: i64 = 0x0804 106const SS_RSA_PSS_RSAE_SHA384: i64 = 0x0805 107const SS_RSA_PSS_RSAE_SHA512: i64 = 0x0806 108 109// ---- record-layer TLSPlaintext header parse / emit ------------- 110// 111// TLSPlaintext { 112// ContentType type; (1 byte) 113// ProtocolVersion legacy; (2 bytes, big-endian, 0x0303) 114// uint16 length; (2 bytes, big-endian, <= 2^14 + 256) 115// opaque fragment[length]; 116// } 117 118const TLS_MAX_RECORD: i64 = 16384 // 2^14 bytes TLSPlaintext cap 119 120// Read the 5-byte record header from buf[0..5]. Writes type, 121// version, length to the caller-supplied *i64 slots. Returns 0 122// on success, -1 if buf_len < 5. 123func tls_read_record_header(buf: *u8, buf_len: i64, 124 out_type: *i64, 125 out_ver: *i64, 126 out_len: *i64) -> i64 { 127 if buf_len < 5 { return -1 } 128 *out_type = buf[0] 129 *out_ver = (buf[1] << 8) | buf[2] 130 *out_len = (buf[3] << 8) | buf[4] 131 return 0 132} 133 134// Write a record header. `buf` must hold >= 5 bytes. length 135// must be <= TLS_MAX_RECORD + 256 (TLSCiphertext allows +256 136// for AEAD overhead). 137func tls_write_record_header(buf: *u8, 138 content_type: i64, 139 length: i64) -> i64 { 140 buf[0] = content_type & 0xFF 141 buf[1] = (TLS_LEGACY_VERSION >> 8) & 0xFF 142 buf[2] = TLS_LEGACY_VERSION & 0xFF 143 buf[3] = (length >> 8) & 0xFF 144 buf[4] = length & 0xFF 145 return 5 146} 147 148// Big-endian 24-bit length (used in Handshake message headers). 149func tls_read_u24_be(buf: *u8, off: i64) -> i64 { 150 return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2] 151} 152 153func tls_write_u24_be(buf: *u8, off: i64, v: i64) -> i64 { 154 buf[off] = (v >> 16) & 0xFF 155 buf[off + 1] = (v >> 8) & 0xFF 156 buf[off + 2] = v & 0xFF 157 return 3 158} 159 160// Big-endian 16-bit (used for TLS lengths, extension lengths, 161// etc.). 162func tls_read_u16_be(buf: *u8, off: i64) -> i64 { 163 return (buf[off] << 8) | buf[off + 1] 164} 165 166func tls_write_u16_be(buf: *u8, off: i64, v: i64) -> i64 { 167 buf[off] = (v >> 8) & 0xFF 168 buf[off + 1] = v & 0xFF 169 return 2 170} 171 172// Compile-only smoke: build then parse a record header for a 173// 42-byte handshake message. 174func main() -> i64 { 175 let buf: *u8 = sys_mmap(64) 176 tls_write_record_header(buf, CT_HANDSHAKE, 42) 177 if buf[0] != CT_HANDSHAKE { return 1 } 178 if buf[1] != 0x03 { return 2 } 179 if buf[2] != 0x03 { return 3 } 180 181 let t: *i64 = sys_mmap(16) as *i64 182 let v: *i64 = sys_mmap(16) as *i64 183 let l: *i64 = sys_mmap(16) as *i64 184 tls_read_record_header(buf, 5, t, v, l) 185 if *t != CT_HANDSHAKE { return 4 } 186 if *l != 42 { return 5 } 187 return 0 188}