lib/quic/src/tls/engine/test.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const quic = @import("../../root.zig");
  3 const tls = @import("../root.zig");
  4 
  5 const limits = tls.Limits{ .max_message = 512 };
  6 const storage_bytes: usize = 4_124;
  7 
  8 const HarnessOptions = struct {
  9     client_expected: ?tls.PublicKey = null,
 10     server_expected_override: ?tls.PublicKey = null,
 11     server_alpn: []const u8 = "tiny/1",
 12 };
 13 
 14 const Harness = struct {
 15     client_bytes: [storage_bytes]u8 align(tls.Storage.storage_alignment),
 16     server_bytes: [storage_bytes]u8 align(tls.Storage.storage_alignment),
 17     client_storage: tls.Storage,
 18     server_storage: tls.Storage,
 19     client: tls.Engine,
 20     server: tls.Engine,
 21 
 22     fn init(self: *Harness, client_expected: ?tls.PublicKey) !void {
 23         return self.initWith(.{ .client_expected = client_expected });
 24     }
 25 
 26     fn initWith(self: *Harness, options: HarnessOptions) !void {
 27         const client_identity = try tls.Identity.fromSeed(@splat(0x11));
 28         const server_identity = try tls.Identity.fromSeed(@splat(0x22));
 29         const server_expected = options.server_expected_override orelse client_identity.public();
 30         self.client_storage = try tls.Storage.init(&self.client_bytes, limits);
 31         self.server_storage = try tls.Storage.init(&self.server_bytes, limits);
 32         self.client = try tls.Engine.init(.{
 33             .role = .client,
 34             .identity = client_identity,
 35             .expected_peer = options.client_expected,
 36             .alpn = "tiny/1",
 37             .transport_parameters = &.{ 0x01, 0x02 },
 38             .server_name = "peer.test",
 39             .random = tls.Random.testing(fixedRandom(0x33, 0x44)),
 40         }, limits, &self.client_storage);
 41         self.server = try tls.Engine.init(.{
 42             .role = .server,
 43             .identity = server_identity,
 44             .expected_peer = server_expected,
 45             .alpn = options.server_alpn,
 46             .transport_parameters = &.{ 0x03, 0x04, 0x05 },
 47             .server_name = "peer.test",
 48             .random = tls.Random.testing(fixedRandom(0x55, 0x66)),
 49         }, limits, &self.server_storage);
 50     }
 51 
 52     fn exchangeInitial(self: *Harness, wire: []u8) !void {
 53         try transfer(&self.client, &self.server, .initial, wire);
 54         try transfer(&self.server, &self.client, .initial, wire);
 55     }
 56 
 57     fn finish(self: *Harness, wire: []u8) !void {
 58         try self.exchangeInitial(wire);
 59         try transfer(&self.server, &self.client, .handshake, wire);
 60         try transfer(&self.client, &self.server, .handshake, wire);
 61     }
 62 
 63     fn deinit(self: *Harness) void {
 64         self.client.deinit();
 65         self.server.deinit();
 66         _ = self.client_storage.deinit();
 67         _ = self.server_storage.deinit();
 68     }
 69 };
 70 
 71 fn fixedRandom(hello: u8, key: u8) tls.FixedRandom {
 72     return .{ .hello = @splat(hello), .key_exchange = @splat(key) };
 73 }
 74 
 75 fn transfer(sender: *tls.Engine, receiver: *tls.Engine, level: tls.Level, wire: []u8) !void {
 76     const count = sender.emit(level, wire);
 77     try std.testing.expect(count != 0);
 78     try receiver.receive(level, wire[0..count]);
 79 }
 80 
 81 fn transferChunked(sender: *tls.Engine, receiver: *tls.Engine, level: tls.Level) !void {
 82     var byte: [1]u8 = undefined;
 83     for (0..2_048) |_| {
 84         const count = sender.emit(level, &byte);
 85         if (count == 0) return;
 86         try std.testing.expectEqual(@as(usize, 1), count);
 87         try receiver.receive(level, &byte);
 88     }
 89     return error.FlightTooLarge;
 90 }
 91 
 92 fn handshakeOffset(bytes: []const u8, wanted: std.crypto.tls.HandshakeType) !usize {
 93     var offset: usize = 0;
 94     for (0..8) |_| {
 95         if (offset == bytes.len) return error.NotFound;
 96         if (bytes.len - offset < 4) return error.Truncated;
 97         const length = (@as(usize, bytes[offset + 1]) << 16) |
 98             (@as(usize, bytes[offset + 2]) << 8) | bytes[offset + 3];
 99         if (length > bytes.len - offset - 4) return error.Truncated;
100         if (bytes[offset] == @backingInt(wanted)) return offset;
101         offset += length + 4;
102     }
103     return error.NotFound;
104 }
105 
106 fn clientExtensionOffset(bytes: []const u8, wanted: std.crypto.tls.ExtensionType) !usize {
107     const hello = try tls.message.decodeClientHello(bytes);
108     var iterator = hello.extensions.iterator();
109     for (0..tls.message.extension_count_max + 1) |_| {
110         const item = try iterator.next() orelse return error.NotFound;
111         if (@backingInt(item.kind) != @backingInt(wanted)) continue;
112         return @intFromPtr(item.data.ptr) - @intFromPtr(bytes.ptr) - 4;
113     }
114     unreachable;
115 }
116 
117 test "RFC 8446 section 4 mutual raw-key loopback handshake" {
118     var harness: Harness = undefined;
119     try harness.init(null);
120     defer harness.deinit();
121     var wire: [2_048]u8 = undefined;
122     try harness.finish(&wire);
123     try std.testing.expectEqual(tls.Status.handshake_complete, harness.client.state());
124     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.server.state());
125     try std.testing.expectEqual(
126         std.crypto.tls.CipherSuite.AES_128_GCM_SHA256,
127         harness.client.cipherSuite().?,
128     );
129     try std.testing.expectEqual(harness.client.cipherSuite(), harness.server.cipherSuite());
130     try std.testing.expectEqual(
131         harness.client.secret(.one_rtt, .write),
132         harness.server.secret(.one_rtt, .read),
133     );
134     try std.testing.expectEqual(
135         harness.client.secret(.one_rtt, .read),
136         harness.server.secret(.one_rtt, .write),
137     );
138     try expectPeers(&harness);
139     harness.client.confirm();
140     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.client.state());
141 }
142 
143 test "RFC 9001 sections 4.1 and 5.7 role status and secret sequence" {
144     var harness: Harness = undefined;
145     try harness.init(null);
146     defer harness.deinit();
147     var wire: [2_048]u8 = undefined;
148     try std.testing.expectEqual(tls.Status.handshaking, harness.client.state());
149     try std.testing.expectEqual(tls.Status.handshaking, harness.server.state());
150     try transfer(&harness.client, &harness.server, .initial, &wire);
151     try std.testing.expect(harness.server.secret(.one_rtt, .write) != null);
152     try std.testing.expectEqual(@as(?tls.Secret, null), harness.server.secret(.one_rtt, .read));
153     try std.testing.expect(std.mem.allEqual(u8, &harness.server.schedule.?.early, 0));
154     try std.testing.expect(std.mem.allEqual(u8, &harness.server.schedule.?.handshake, 0));
155     try std.testing.expect(std.mem.allEqual(u8, &harness.server.schedule.?.master, 0));
156     try transfer(&harness.server, &harness.client, .initial, &wire);
157     try std.testing.expectEqual(
158         harness.client.secret(.handshake, .write),
159         harness.server.secret(.handshake, .read),
160     );
161     try std.testing.expectEqual(
162         harness.client.secret(.handshake, .read),
163         harness.server.secret(.handshake, .write),
164     );
165     try transfer(&harness.server, &harness.client, .handshake, &wire);
166     try std.testing.expectEqual(tls.Status.handshaking, harness.client.state());
167     try std.testing.expectEqual(tls.Status.handshaking, harness.server.state());
168     try std.testing.expectEqual(@as(?tls.Secret, null), harness.server.secret(.one_rtt, .read));
169     try transfer(&harness.client, &harness.server, .handshake, &wire);
170     try std.testing.expectEqual(tls.Status.handshake_complete, harness.client.state());
171     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.server.state());
172     try std.testing.expectEqual(
173         harness.client.secret(.one_rtt, .write),
174         harness.server.secret(.one_rtt, .read),
175     );
176     try std.testing.expectEqual(@as(?tls.Secret, null), harness.server.secret(.handshake, .read));
177     try std.testing.expect(std.mem.allEqual(
178         u8,
179         &harness.server.schedule.?.client_handshake,
180         0,
181     ));
182     try std.testing.expect(std.mem.allEqual(
183         u8,
184         &harness.server.schedule.?.server_handshake,
185         0,
186     ));
187     harness.client.confirm();
188     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.client.state());
189     try std.testing.expectEqual(@as(?tls.Secret, null), harness.client.secret(.handshake, .write));
190 }
191 
192 test "RFC 9000 section 13.3 emitted handshake bytes stay readable for a resent CRYPTO frame" {
193     var harness: Harness = undefined;
194     try harness.init(null);
195     defer harness.deinit();
196     var wire: [512]u8 = undefined;
197     try std.testing.expectEqual(@as(usize, 0), harness.client.emitted(.initial).len);
198     const head = harness.client.emit(.initial, wire[0..16]);
199     try std.testing.expectEqual(@as(usize, 16), head);
200     try std.testing.expectEqualSlices(u8, wire[0..head], harness.client.emitted(.initial));
201     const tail = harness.client.emit(.initial, wire[head..]);
202     try std.testing.expect(tail != 0);
203     const flight = harness.client.emitted(.initial);
204     try std.testing.expectEqualSlices(u8, wire[0 .. head + tail], flight);
205     try std.testing.expectEqual(@as(usize, 0), harness.client.emitted(.handshake).len);
206     try std.testing.expectEqual(@as(usize, 0), harness.client.emitted(.one_rtt).len);
207 }
208 
209 test "RFC 8446 section 4 partial handshake messages remain buffered" {
210     var harness: Harness = undefined;
211     try harness.init(null);
212     defer harness.deinit();
213     try transferChunked(&harness.client, &harness.server, .initial);
214     try transferChunked(&harness.server, &harness.client, .initial);
215     try transferChunked(&harness.server, &harness.client, .handshake);
216     try transferChunked(&harness.client, &harness.server, .handshake);
217     try std.testing.expectEqual(tls.Status.handshake_complete, harness.client.state());
218     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.server.state());
219 }
220 
221 test "RFC 9001 section 4.1.3 partial messages cannot cross encryption levels" {
222     var harness: Harness = undefined;
223     try harness.init(null);
224     defer harness.deinit();
225     var wire: [2_048]u8 = undefined;
226     const count = harness.client.emit(.initial, &wire);
227     wire[count] = @backingInt(std.crypto.tls.HandshakeType.certificate);
228     wire[count + 1] = 0;
229     try harness.server.receive(.initial, wire[0 .. count + 2]);
230     try std.testing.expectError(
231         error.TlsAlert,
232         harness.server.receive(.handshake, &.{0}),
233     );
234     try std.testing.expectEqual(tls.Alert.unexpected_message, harness.server.alert().?);
235 }
236 
237 test "RFC 8446 section 4.1.3 ChaCha20 handshake confirms with matching secrets" {
238     var harness: Harness = undefined;
239     try harness.init(null);
240     defer harness.deinit();
241     var wire: [2_048]u8 = undefined;
242     const count = harness.client.emit(.initial, &wire);
243     const hello = try tls.message.decodeClientHello(wire[0..count]);
244     const offset = @intFromPtr(hello.cipher_suites.ptr) - @intFromPtr(wire[0..].ptr);
245     const chacha = @backingInt(std.crypto.tls.CipherSuite.CHACHA20_POLY1305_SHA256);
246     wire[offset] = @truncate(chacha >> 8);
247     wire[offset + 1] = @truncate(chacha);
248     wire[offset + 2] = @truncate(chacha >> 8);
249     wire[offset + 3] = @truncate(chacha);
250     harness.client.transcript = std.crypto.hash.sha2.Sha256.init(.{});
251     harness.client.transcript.update(wire[0..count]);
252     try harness.server.receive(.initial, wire[0..count]);
253     const response_count = harness.server.emit(.initial, &wire);
254     const response = try tls.message.decodeServerHello(wire[0..response_count]);
255     try std.testing.expectEqual(chacha, response.cipher_suite);
256     try std.testing.expectEqual(
257         std.crypto.tls.CipherSuite.CHACHA20_POLY1305_SHA256,
258         harness.server.cipherSuite().?,
259     );
260     try harness.client.receive(.initial, wire[0..response_count]);
261     try transfer(&harness.server, &harness.client, .handshake, &wire);
262     try transfer(&harness.client, &harness.server, .handshake, &wire);
263     harness.client.confirm();
264     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.client.state());
265     try std.testing.expectEqual(tls.Status.handshake_confirmed, harness.server.state());
266     try std.testing.expectEqual(harness.client.cipherSuite(), harness.server.cipherSuite());
267     try std.testing.expectEqual(
268         harness.client.secret(.one_rtt, .write),
269         harness.server.secret(.one_rtt, .read),
270     );
271     try std.testing.expectEqual(
272         harness.client.secret(.one_rtt, .read),
273         harness.server.secret(.one_rtt, .write),
274     );
275 }
276 
277 test "RFC 8446 section 4.1.4 HelloRetryRequest aborts" {
278     var harness: Harness = undefined;
279     try harness.init(null);
280     defer harness.deinit();
281     var bytes: [128]u8 = undefined;
282     var output = quic.cursor.Write.init(&bytes);
283     try tls.message.profile.encodeServerHello(.{
284         .random = std.crypto.tls.hello_retry_request_sequence,
285         .key_share = @splat(0xa5),
286         .cipher_suite = .AES_128_GCM_SHA256,
287     }, &output);
288     try std.testing.expectError(
289         error.TlsAlert,
290         harness.client.receive(.initial, output.written()),
291     );
292     try std.testing.expectEqual(tls.Alert.handshake_failure, harness.client.alert().?);
293 }
294 
295 test "RFC 8446 section 4.1.3 ServerHello downgrade sentinel aborts" {
296     var harness: Harness = undefined;
297     try harness.init(null);
298     defer harness.deinit();
299     var random: [32]u8 = @splat(0xa5);
300     @memcpy(random[24..], "DOWNGRD\x01");
301     var bytes: [128]u8 = undefined;
302     var output = quic.cursor.Write.init(&bytes);
303     try tls.message.profile.encodeServerHello(.{
304         .random = random,
305         .key_share = @splat(0x5a),
306         .cipher_suite = .AES_128_GCM_SHA256,
307     }, &output);
308     const hello = try tls.message.decodeServerHello(output.written());
309     const version = (try tls.message.findExtension(hello.extensions, .supported_versions)).?;
310     const version_offset = @intFromPtr(version.ptr) - @intFromPtr(bytes[0..].ptr);
311     bytes[version_offset + 1] = 0x03;
312     try std.testing.expectError(
313         error.TlsAlert,
314         harness.client.receive(.initial, output.written()),
315     );
316     try std.testing.expectEqual(tls.Alert.illegal_parameter, harness.client.alert().?);
317 }
318 
319 test "RFC 8446 section 4.2.8.2 X25519 all-zero shared secret aborts" {
320     var harness: Harness = undefined;
321     try harness.init(null);
322     defer harness.deinit();
323     var bytes: [128]u8 = undefined;
324     var output = quic.cursor.Write.init(&bytes);
325     try tls.message.profile.encodeServerHello(.{
326         .random = @splat(0xa5),
327         .key_share = @splat(0),
328         .cipher_suite = .AES_128_GCM_SHA256,
329     }, &output);
330     try std.testing.expectError(
331         error.TlsAlert,
332         harness.client.receive(.initial, output.written()),
333     );
334     try std.testing.expectEqual(tls.Alert.illegal_parameter, harness.client.alert().?);
335 }
336 
337 test "RFC 9001 section 6 KeyUpdate aborts with unexpected message" {
338     var harness: Harness = undefined;
339     try harness.init(null);
340     defer harness.deinit();
341     const bytes = [_]u8{ @backingInt(std.crypto.tls.HandshakeType.key_update), 0, 0, 1, 0 };
342     try std.testing.expectError(error.TlsAlert, harness.server.receive(.one_rtt, &bytes));
343     try std.testing.expectEqual(tls.Alert.unexpected_message, harness.server.alert().?);
344 }
345 
346 const ticket_type = @backingInt(std.crypto.tls.HandshakeType.new_session_ticket);
347 const session_ticket = [_]u8{ ticket_type, 0, 0, 14, 0, 0, 0, 60, 1, 2, 3, 4, 0, 0, 1, 90, 0, 0 };
348 
349 test "RFC 8446 section 4.6.1 client parses a NewSessionTicket" {
350     var harness: Harness = undefined;
351     try harness.init(null);
352     defer harness.deinit();
353     try harness.client.receive(.one_rtt, &session_ticket);
354     try std.testing.expectEqual(@as(?tls.Alert, null), harness.client.alert());
355 }
356 
357 test "RFC 8446 section 4.6.1 empty ticket aborts with decode error" {
358     var harness: Harness = undefined;
359     try harness.init(null);
360     defer harness.deinit();
361     const bytes = [_]u8{ ticket_type, 0, 0, 13, 0, 0, 0, 60, 1, 2, 3, 4, 0, 0, 0, 0, 0 };
362     try std.testing.expectError(error.TlsAlert, harness.client.receive(.one_rtt, &bytes));
363     try std.testing.expectEqual(tls.Alert.decode_error, harness.client.alert().?);
364 }
365 
366 test "RFC 8446 section 4.6.1 server rejects a NewSessionTicket" {
367     var harness: Harness = undefined;
368     try harness.init(null);
369     defer harness.deinit();
370     try std.testing.expectError(error.TlsAlert, harness.server.receive(.one_rtt, &session_ticket));
371     try std.testing.expectEqual(tls.Alert.unexpected_message, harness.server.alert().?);
372 }
373 
374 test "RFC 8446 section 4.4.2.4 empty client Certificate aborts" {
375     var harness: Harness = undefined;
376     try harness.init(null);
377     defer harness.deinit();
378     var wire: [2_048]u8 = undefined;
379     try transfer(&harness.client, &harness.server, .initial, &wire);
380     var output = quic.cursor.Write.init(&wire);
381     try tls.message.encodeCertificate(.{
382         .request_context = &.{},
383         .entries = .{ .bytes = &.{} },
384     }, &output);
385     try std.testing.expectError(
386         error.TlsAlert,
387         harness.server.receive(.handshake, output.written()),
388     );
389     try std.testing.expectEqual(tls.Alert.certificate_required, harness.server.alert().?);
390 }
391 
392 test "RFC 8446 section 4.4.2.4 empty server Certificate uses decode error" {
393     var harness: Harness = undefined;
394     try harness.init(null);
395     defer harness.deinit();
396     var wire: [2_048]u8 = undefined;
397     try harness.exchangeInitial(&wire);
398     const count = harness.server.emit(.handshake, &wire);
399     const certificate_offset = try handshakeOffset(wire[0..count], .certificate);
400     try harness.client.receive(.handshake, wire[0..certificate_offset]);
401     var empty: [16]u8 = undefined;
402     var output = quic.cursor.Write.init(&empty);
403     try tls.message.encodeCertificate(.{
404         .request_context = &.{},
405         .entries = .{ .bytes = &.{} },
406     }, &output);
407     try std.testing.expectError(
408         error.TlsAlert,
409         harness.client.receive(.handshake, output.written()),
410     );
411     try std.testing.expectEqual(tls.Alert.decode_error, harness.client.alert().?);
412 }
413 
414 fn expectPeers(harness: *const Harness) !void {
415     const client_peer = harness.client.peer().?;
416     const server_peer = harness.server.peer().?;
417     try std.testing.expectEqual(harness.server.config.identity.public(), client_peer.public_key);
418     try std.testing.expectEqual(harness.client.config.identity.public(), server_peer.public_key);
419     try std.testing.expectEqualStrings("tiny/1", client_peer.alpn);
420     try std.testing.expectEqualStrings("tiny/1", server_peer.alpn);
421     try std.testing.expectEqualSlices(u8, &.{ 0x03, 0x04, 0x05 }, client_peer.transport_parameters);
422     try std.testing.expectEqualSlices(u8, &.{ 0x01, 0x02 }, server_peer.transport_parameters);
423 }
424 
425 test "RFC 8446 section 4.4.2 wrong expected raw key aborts" {
426     var harness: Harness = undefined;
427     try harness.init(@splat(0xaa));
428     defer harness.deinit();
429     var wire: [2_048]u8 = undefined;
430     try harness.exchangeInitial(&wire);
431     const count = harness.server.emit(.handshake, &wire);
432     try std.testing.expectError(error.TlsAlert, harness.client.receive(.handshake, wire[0..count]));
433     try std.testing.expectEqual(tls.Alert.bad_certificate, harness.client.alert().?);
434 }
435 
436 test "RFC 8446 section 4.4.2 wrong server-side expected raw key aborts" {
437     var harness: Harness = undefined;
438     try harness.initWith(.{ .server_expected_override = @splat(0xaa) });
439     defer harness.deinit();
440     var wire: [2_048]u8 = undefined;
441     try harness.exchangeInitial(&wire);
442     try transfer(&harness.server, &harness.client, .handshake, &wire);
443     const count = harness.client.emit(.handshake, &wire);
444     try std.testing.expectError(
445         error.TlsAlert,
446         harness.server.receive(.handshake, wire[0..count]),
447     );
448     try std.testing.expectEqual(tls.Alert.bad_certificate, harness.server.alert().?);
449 }
450 
451 test "RFC 8446 section 4.4.3 modified CertificateVerify aborts" {
452     var harness: Harness = undefined;
453     try harness.init(null);
454     defer harness.deinit();
455     var wire: [2_048]u8 = undefined;
456     try harness.exchangeInitial(&wire);
457     const count = harness.server.emit(.handshake, &wire);
458     const offset = try handshakeOffset(wire[0..count], .certificate_verify);
459     wire[offset + 10] ^= 1;
460     try std.testing.expectError(error.TlsAlert, harness.client.receive(.handshake, wire[0..count]));
461     try std.testing.expectEqual(tls.Alert.decrypt_error, harness.client.alert().?);
462 }
463 
464 test "RFC 8446 section 4.4.4 modified Finished aborts" {
465     var harness: Harness = undefined;
466     try harness.init(null);
467     defer harness.deinit();
468     var wire: [2_048]u8 = undefined;
469     try harness.exchangeInitial(&wire);
470     const count = harness.server.emit(.handshake, &wire);
471     const offset = try handshakeOffset(wire[0..count], .finished);
472     wire[offset + 4] ^= 1;
473     try std.testing.expectError(error.TlsAlert, harness.client.receive(.handshake, wire[0..count]));
474     try std.testing.expectEqual(tls.Alert.decrypt_error, harness.client.alert().?);
475 }
476 
477 test "RFC 9001 section 8.1 missing ClientHello ALPN aborts" {
478     try expectMissingClientExtension(
479         .application_layer_protocol_negotiation,
480         .no_application_protocol,
481     );
482 }
483 
484 test "RFC 9001 section 8.1 disjoint ClientHello ALPN aborts" {
485     var harness: Harness = undefined;
486     try harness.initWith(.{ .server_alpn = "other/1" });
487     defer harness.deinit();
488     var wire: [2_048]u8 = undefined;
489     const count = harness.client.emit(.initial, &wire);
490     try std.testing.expectError(
491         error.TlsAlert,
492         harness.server.receive(.initial, wire[0..count]),
493     );
494     try std.testing.expectEqual(tls.Alert.no_application_protocol, harness.server.alert().?);
495 }
496 
497 test "RFC 9001 section 8.2 missing QUIC transport parameters aborts" {
498     try expectMissingClientExtension(.quic_transport_parameters, .missing_extension);
499 }
500 
501 fn expectMissingClientExtension(
502     kind: std.crypto.tls.ExtensionType,
503     alert_value: tls.Alert,
504 ) !void {
505     var harness: Harness = undefined;
506     try harness.init(null);
507     defer harness.deinit();
508     var wire: [2_048]u8 = undefined;
509     const count = harness.client.emit(.initial, &wire);
510     const offset = try clientExtensionOffset(wire[0..count], kind);
511     wire[offset] = 0xaa;
512     wire[offset + 1] = 0xaa;
513     try std.testing.expectError(error.TlsAlert, harness.server.receive(.initial, wire[0..count]));
514     try std.testing.expectEqual(alert_value, harness.server.alert().?);
515 }
516 
517 test "RFC 8446 section 7.1 Engine teardown erases secrets and storage" {
518     var harness: Harness = undefined;
519     try harness.init(null);
520     var wire: [2_048]u8 = undefined;
521     try harness.finish(&wire);
522     try std.testing.expect(!std.mem.allEqual(u8, std.mem.asBytes(&harness.client), 0));
523     harness.deinit();
524     try std.testing.expect(std.mem.allEqual(u8, std.mem.asBytes(&harness.client), 0));
525     try std.testing.expect(std.mem.allEqual(u8, std.mem.asBytes(&harness.server), 0));
526     try std.testing.expect(std.mem.allEqual(u8, &harness.client_bytes, 0));
527     try std.testing.expect(std.mem.allEqual(u8, &harness.server_bytes, 0));
528 }
529 
530 test "RFC 8446 section 4 handshake message maximum and maximum plus one" {
531     const small_limits = tls.Limits{ .max_message = 256 };
532     const capacity = try tls.Capacity.derive(small_limits);
533     try std.testing.expectEqual(@as(usize, 2_076), capacity.storage_bytes);
534     var bytes: [2_076]u8 align(tls.Storage.storage_alignment) = undefined;
535     var owner = try tls.Storage.init(&bytes, small_limits);
536     const identity = try tls.Identity.fromSeed(@splat(0x77));
537     var engine = try tls.Engine.init(.{
538         .role = .client,
539         .identity = identity,
540         .expected_peer = null,
541         .alpn = "a",
542         .transport_parameters = &.{},
543         .server_name = null,
544         .random = tls.Random.testing(fixedRandom(0x88, 0x99)),
545     }, small_limits, &owner);
546     var message: [260]u8 = @splat(0);
547     message[0] = @backingInt(std.crypto.tls.HandshakeType.new_session_ticket);
548     message[2] = 1;
549     message[14] = 243;
550     try engine.receive(.one_rtt, &message);
551     var too_large = [_]u8{
552         @backingInt(std.crypto.tls.HandshakeType.new_session_ticket), 0, 1, 1,
553     };
554     try std.testing.expectError(error.MessageTooLarge, engine.receive(.one_rtt, &too_large));
555     engine.deinit();
556     _ = owner.deinit();
557 }