Skip to content

Commit 342c943

Browse files
committed
updates added tls tests more
1 parent f057137 commit 342c943

4 files changed

Lines changed: 1482 additions & 2 deletions

File tree

lang/tests/tls/src/api_surface.ch

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// ============================================================================
2+
// API Surface + TLS 1.2 Session Ticket Tests
3+
// ============================================================================
4+
// Unit coverage for previously-unexercised public APIs (handshake_params_init,
5+
// ecp curve selection, ssl_read_new_session_ticket guards) plus a live TLS 1.2
6+
// session-ticket exchange against Python/OpenSSL.
7+
// Ports used: 20130.
8+
// ============================================================================
9+
10+
using namespace tls
11+
using std::string_view
12+
13+
// ─── handshake_params_init zeroes all sensitive buffers ─────────────────────
14+
@test
15+
public func API_handshake_params_init_zeroes(env : &mut TestEnv) {
16+
var hs_mem = malloc(sizeof(HandshakeParams)) as *mut HandshakeParams
17+
if(hs_mem == null) { env.error("alloc failed"); return }
18+
19+
// Poison the memory first so init provably writes the fields it owns.
20+
memset(hs_mem as *mut void, 0xAB, sizeof(HandshakeParams))
21+
22+
handshake_params_init(hs_mem)
23+
24+
var i : size_t = 0
25+
while(i < 64) {
26+
if(hs_mem.randbytes[i] != 0) { env.error("randbytes must be zeroed"); return }
27+
i += 1
28+
}
29+
i = 0
30+
while(i < 256) {
31+
if(hs_mem.premaster[i] != 0) { env.error("premaster must be zeroed"); return }
32+
i += 1
33+
}
34+
if(hs_mem.premaster_len != 0) { env.error("premaster_len must start at 0") }
35+
if(hs_mem.psk_len != 0) { env.error("psk_len must start at 0") }
36+
if(hs_mem.hello_retry_requested) { env.error("hello_retry_requested must start false") }
37+
if(hs_mem.psk_accepted) { env.error("psk_accepted must start false") }
38+
39+
unsafe { dealloc hs_mem }
40+
}
41+
42+
// ─── ecp_select_curve switches between P-256 and P-384 domain parameters ────
43+
@test
44+
public func API_ecp_curve_selection_params(env : &mut TestEnv) {
45+
// P-256 (GLOBAL_CURVE == 0)
46+
ecp_select_curve(0)
47+
if(ecp_curve_id() != 0) { env.error("curve id should be 0 for P-256"); return }
48+
49+
unsafe var p : Mpi; unsafe var n : Mpi; unsafe var gx : Mpi; unsafe var gy : Mpi; unsafe var b : Mpi
50+
ecp_curve_p(&raw mut p); ecp_curve_n(&raw mut n)
51+
ecp_curve_gx(&raw mut gx); ecp_curve_gy(&raw mut gy); ecp_curve_b(&raw mut b)
52+
53+
// P-256 prime: 2^256 - 2^224 + 2^192 + 2^96 - 1 → 256 bits
54+
if(mpi_bitlen(&raw mut p) != 256) { env.error("P-256 p bitlen should be 256"); return }
55+
// Group order n is also 256 bits
56+
if(mpi_bitlen(&raw mut n) != 256) { env.error("P-256 n bitlen should be 256"); return }
57+
58+
// Generator coordinates are canonical 256-bit values (nonzero, < p).
59+
if(mpi_cmp(&raw mut gx, &raw mut p) >= 0) { env.error("P-256 Gx must be < p"); return }
60+
if(mpi_is_zero(&raw mut gx)) { env.error("P-256 Gx must not be zero"); return }
61+
if(mpi_cmp(&raw mut gy, &raw mut p) >= 0) { env.error("P-256 Gy must be < p"); return }
62+
63+
// Curve equation check: y^2 mod p == (x^3 + a*x + b) mod p with a = p-3.
64+
unsafe var y2 : Mpi; unsafe var x3 : Mpi; unsafe var ax : Mpi; unsafe var a : Mpi
65+
unsafe var rhs : Mpi
66+
unsafe var three : Mpi
67+
mpi_lset(&raw mut three, 3)
68+
mpi_sub(&raw mut a, &raw mut p, &raw mut three)
69+
mpi_mul(&raw mut y2, &raw mut gy, &raw mut gy)
70+
mpi_mod(&raw mut y2, &raw mut y2, &raw mut p)
71+
mpi_mul(&raw mut x3, &raw mut gx, &raw mut gx)
72+
mpi_mul(&raw mut x3, &raw mut x3, &raw mut gx)
73+
mpi_mul(&raw mut ax, &raw mut a, &raw mut gx)
74+
mpi_add(&raw mut rhs, &raw mut x3, &raw mut ax)
75+
mpi_add(&raw mut rhs, &raw mut rhs, &raw mut b)
76+
mpi_mod(&raw mut rhs, &raw mut rhs, &raw mut p)
77+
if(mpi_cmp(&raw mut y2, &raw mut rhs) != 0) {
78+
env.error("P-256 generator must satisfy the curve equation")
79+
return
80+
}
81+
82+
// P-384 (GLOBAL_CURVE == 1)
83+
ecp_select_curve(1)
84+
if(ecp_curve_id() != 1) { env.error("curve id should be 1 for P-384"); return }
85+
86+
unsafe var p384 : Mpi; unsafe var gx384 : Mpi; unsafe var b384 : Mpi
87+
ecp_curve_p(&raw mut p384)
88+
ecp_curve_gx(&raw mut gx384)
89+
ecp_curve_b(&raw mut b384)
90+
91+
// P-384 prime: 2^384 - 2^128 - 2^96 + 2^32 - 1 → 384 bits
92+
if(mpi_bitlen(&raw mut p384) != 384) { env.error("P-384 p bitlen should be 384"); return }
93+
if(mpi_bitlen(&raw mut gx384) == 0) { env.error("P-384 Gx must be nonzero"); return }
94+
if(mpi_cmp(&raw mut gx384, &raw mut p384) >= 0) { env.error("P-384 Gx must be < p"); return }
95+
96+
// Restore the default so any later logic relying on global state is sane.
97+
ecp_select_curve(0)
98+
}
99+
100+
// ─── ssl_read_new_session_ticket without a transport fails cleanly ──────────
101+
@test
102+
public func API_ssl_read_new_session_ticket_no_socket_fails(env : &mut TestEnv) {
103+
unsafe var ctx : SSLContext; ssl_init(&raw mut ctx)
104+
105+
var ret = ssl_read_new_session_ticket(&raw mut ctx)
106+
if(ret >= 0) {
107+
env.error("reading a session ticket with no transport must fail")
108+
}
109+
ssl_free(&raw mut ctx)
110+
}
111+
112+
// ─── TLS 1.2 NewSessionTicket: received, decrypted and stored post-handshake
113+
// OpenSSL servers send an encrypted NewSessionTicket right after ServerFinished
114+
// in TLS 1.2. The client must decrypt it through the active transform, store
115+
// the ticket + master secret in ssl.session, and keep the connection usable.
116+
@test
117+
@test.timeout(60000)
118+
public func E2E_tls12_session_ticket_received_and_stored(env : &mut TestEnv) {
119+
write_tls_python_utils()
120+
test_kill_port(20130u)
121+
test_server_wait()
122+
test_py_run_foreground(string_view("cert /tmp/tls_20130_cert.pem /tmp/tls_20130_key.pem localhost rsa"))
123+
// OpenSSL 3 disables static-RSA suites at the default security level; pin
124+
// them server-side so the TLS 1.2 RSA key-exchange path is negotiated.
125+
// srv handles exactly one exchange (recv → OK), which is all we need here.
126+
test_py_run_background(string_view("srv /tmp/tls_20130_cert.pem /tmp/tls_20130_key.pem 20130 1.2 AES128-GCM-SHA256:@SECLEVEL=0"))
127+
test_server_wait()
128+
129+
unsafe var ctx : SSLContext; ssl_init(&raw mut ctx)
130+
var config = ssl_config_init(SSL_IS_CLIENT)
131+
config.authmode = SSL_VERIFY_NONE
132+
config.max_tls_version = SSL_VERSION_TLS1_2
133+
config.ciphersuite_list[0] = TLS_RSA_WITH_AES_128_GCM_SHA256 as u16
134+
config.ciphersuite_count = 1
135+
ssl_set_config(&raw mut ctx, &raw mut config)
136+
137+
var ret = tls_connect(&raw mut ctx, "127.0.0.1", 20130u)
138+
if(ret < 0) {
139+
env.error("TLS12 ticket: connect failed")
140+
ssl_free(&raw mut ctx)
141+
test_kill_port(20130u)
142+
return
143+
}
144+
145+
if(ctx.session == null) { env.error("TLS12 ticket: session not allocated"); ssl_free(&raw mut ctx); test_kill_port(20130u); return }
146+
147+
// The server's NewSessionTicket arrives before its app-data response;
148+
// pull it explicitly through the dedicated post-handshake API.
149+
ret = ssl_read_new_session_ticket(&raw mut ctx)
150+
if(ret != 0) {
151+
// Legitimate gap: record what happened but do not mask it as success.
152+
env.error("TLS12 ticket: ssl_read_new_session_ticket did not accept the NST")
153+
} else {
154+
if(ctx.session.ticket == null || ctx.session.ticket_len == 0) {
155+
env.error("TLS12 ticket: ticket was not stored after processing NST")
156+
}
157+
var ms_nonzero = false
158+
var mi : size_t = 0
159+
while(mi < 48) {
160+
if(ctx.session.master[mi] != 0) { ms_nonzero = true }
161+
mi += 1
162+
}
163+
if(!ms_nonzero) { env.error("TLS12 ticket: master secret missing from session") }
164+
}
165+
166+
// The connection must remain fully usable afterwards.
167+
var ping = "t\0" as *char
168+
ssl_write(&raw mut ctx, ping as *u8, 1)
169+
unsafe var buf : [64]u8
170+
var n = ssl_read(&raw mut ctx, &raw mut buf[0], 64)
171+
if(n != 2 || buf[0] != 79 || buf[1] != 75) {
172+
env.error("TLS12 ticket: connection unusable after reading NST")
173+
}
174+
175+
ssl_close_notify(&raw mut ctx)
176+
ssl_free(&raw mut ctx)
177+
test_kill_port(20130u)
178+
}

0 commit comments

Comments
 (0)