xref: /freebsd/crypto/openssl/test/recipes/70-test_sslrecords.t (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1*e0c4386eSCy Schubert#! /usr/bin/env perl
2*e0c4386eSCy Schubert# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert#
4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License").  You may not use
5*e0c4386eSCy Schubert# this file except in compliance with the License.  You can obtain a copy
6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert
9*e0c4386eSCy Schubertuse strict;
10*e0c4386eSCy Schubertuse feature 'state';
11*e0c4386eSCy Schubert
12*e0c4386eSCy Schubertuse OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
13*e0c4386eSCy Schubertuse OpenSSL::Test::Utils;
14*e0c4386eSCy Schubertuse TLSProxy::Proxy;
15*e0c4386eSCy Schubert
16*e0c4386eSCy Schubertmy $test_name = "test_sslrecords";
17*e0c4386eSCy Schubertsetup($test_name);
18*e0c4386eSCy Schubert
19*e0c4386eSCy Schubertplan skip_all => "TLSProxy isn't usable on $^O"
20*e0c4386eSCy Schubert    if $^O =~ /^(VMS)$/;
21*e0c4386eSCy Schubert
22*e0c4386eSCy Schubertplan skip_all => "$test_name needs the dynamic engine feature enabled"
23*e0c4386eSCy Schubert    if disabled("engine") || disabled("dynamic-engine");
24*e0c4386eSCy Schubert
25*e0c4386eSCy Schubertplan skip_all => "$test_name needs the sock feature enabled"
26*e0c4386eSCy Schubert    if disabled("sock");
27*e0c4386eSCy Schubert
28*e0c4386eSCy Schubertplan skip_all => "$test_name needs TLSv1.2 enabled"
29*e0c4386eSCy Schubert    if disabled("tls1_2");
30*e0c4386eSCy Schubert
31*e0c4386eSCy Schubert$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
32*e0c4386eSCy Schubertmy $proxy = TLSProxy::Proxy->new(
33*e0c4386eSCy Schubert    \&add_empty_recs_filter,
34*e0c4386eSCy Schubert    cmdstr(app(["openssl"]), display => 1),
35*e0c4386eSCy Schubert    srctop_file("apps", "server.pem"),
36*e0c4386eSCy Schubert    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
37*e0c4386eSCy Schubert);
38*e0c4386eSCy Schubert
39*e0c4386eSCy Schubertmy $boundary_test_type;
40*e0c4386eSCy Schubertmy $fatal_alert = 0;    # set by filters at expected fatal alerts
41*e0c4386eSCy Schubert
42*e0c4386eSCy Schubert#Test 1: Injecting out of context empty records should fail
43*e0c4386eSCy Schubertmy $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
44*e0c4386eSCy Schubertmy $inject_recs_num = 1;
45*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
46*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
47*e0c4386eSCy Schubert$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
48*e0c4386eSCy Schubertplan tests => 20;
49*e0c4386eSCy Schubertok($fatal_alert, "Out of context empty records test");
50*e0c4386eSCy Schubert
51*e0c4386eSCy Schubert#Test 2: Injecting in context empty records should succeed
52*e0c4386eSCy Schubert$proxy->clear();
53*e0c4386eSCy Schubert$content_type = TLSProxy::Record::RT_HANDSHAKE;
54*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
55*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
56*e0c4386eSCy Schubert$proxy->start();
57*e0c4386eSCy Schubertok(TLSProxy::Message->success(), "In context empty records test");
58*e0c4386eSCy Schubert
59*e0c4386eSCy Schubert#Test 3: Injecting too many in context empty records should fail
60*e0c4386eSCy Schubert$fatal_alert = 0;
61*e0c4386eSCy Schubert$proxy->clear();
62*e0c4386eSCy Schubert#We allow 32 consecutive in context empty records
63*e0c4386eSCy Schubert$inject_recs_num = 33;
64*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
65*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
66*e0c4386eSCy Schubert$proxy->start();
67*e0c4386eSCy Schubertok($fatal_alert, "Too many in context empty records test");
68*e0c4386eSCy Schubert
69*e0c4386eSCy Schubert#Test 4: Injecting a fragmented fatal alert should fail. We expect the server to
70*e0c4386eSCy Schubert#        send back an alert of its own because it cannot handle fragmented
71*e0c4386eSCy Schubert#        alerts
72*e0c4386eSCy Schubert$fatal_alert = 0;
73*e0c4386eSCy Schubert$proxy->clear();
74*e0c4386eSCy Schubert$proxy->filter(\&add_frag_alert_filter);
75*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
76*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
77*e0c4386eSCy Schubert$proxy->start();
78*e0c4386eSCy Schubertok($fatal_alert, "Fragmented alert records test");
79*e0c4386eSCy Schubert
80*e0c4386eSCy Schubert#Run some SSLv2 ClientHello tests
81*e0c4386eSCy Schubert
82*e0c4386eSCy Schubertuse constant {
83*e0c4386eSCy Schubert    TLSV1_2_IN_SSLV2 => 0,
84*e0c4386eSCy Schubert    SSLV2_IN_SSLV2 => 1,
85*e0c4386eSCy Schubert    FRAGMENTED_IN_TLSV1_2 => 2,
86*e0c4386eSCy Schubert    FRAGMENTED_IN_SSLV2 => 3,
87*e0c4386eSCy Schubert    ALERT_BEFORE_SSLV2 => 4
88*e0c4386eSCy Schubert};
89*e0c4386eSCy Schubert
90*e0c4386eSCy Schubert# The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
91*e0c4386eSCy Schubert# because in a SSLv2 ClientHello we can't send extentions to indicate
92*e0c4386eSCy Schubert# which signature algorithm we want to use, and the default is SHA1.
93*e0c4386eSCy Schubert
94*e0c4386eSCy Schubert#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
95*e0c4386eSCy Schubertmy $sslv2testtype = TLSV1_2_IN_SSLV2;
96*e0c4386eSCy Schubert$proxy->clear();
97*e0c4386eSCy Schubert$proxy->filter(\&add_sslv2_filter);
98*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
99*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3 -legacy_renegotiation");
100*e0c4386eSCy Schubert$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
101*e0c4386eSCy Schubert$proxy->start();
102*e0c4386eSCy Schubertok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
103*e0c4386eSCy Schubert
104*e0c4386eSCy Schubert#Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
105*e0c4386eSCy Schubert#        support this so it should fail. We actually treat it as an unknown
106*e0c4386eSCy Schubert#        protocol so we don't even send an alert in this case.
107*e0c4386eSCy Schubert$sslv2testtype = SSLV2_IN_SSLV2;
108*e0c4386eSCy Schubert$proxy->clear();
109*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
110*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
111*e0c4386eSCy Schubert$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
112*e0c4386eSCy Schubert$proxy->start();
113*e0c4386eSCy Schubertok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
114*e0c4386eSCy Schubert
115*e0c4386eSCy Schubert#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
116*e0c4386eSCy Schubert#        at all, but it gives us confidence that Test 8 fails for the right
117*e0c4386eSCy Schubert#        reasons
118*e0c4386eSCy Schubert$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
119*e0c4386eSCy Schubert$proxy->clear();
120*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
121*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
122*e0c4386eSCy Schubert$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
123*e0c4386eSCy Schubert$proxy->start();
124*e0c4386eSCy Schubertok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
125*e0c4386eSCy Schubert
126*e0c4386eSCy Schubert#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
127*e0c4386eSCy Schubert#        record; and another TLS1.2 record. This isn't allowed so should fail
128*e0c4386eSCy Schubert$sslv2testtype = FRAGMENTED_IN_SSLV2;
129*e0c4386eSCy Schubert$proxy->clear();
130*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
131*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
132*e0c4386eSCy Schubert$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
133*e0c4386eSCy Schubert$proxy->start();
134*e0c4386eSCy Schubertok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
135*e0c4386eSCy Schubert
136*e0c4386eSCy Schubert#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
137*e0c4386eSCy Schubert#        fail because an SSLv2 ClientHello must be the first record.
138*e0c4386eSCy Schubert$sslv2testtype = ALERT_BEFORE_SSLV2;
139*e0c4386eSCy Schubert$proxy->clear();
140*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
141*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
142*e0c4386eSCy Schubert$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
143*e0c4386eSCy Schubert$proxy->start();
144*e0c4386eSCy Schubertok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
145*e0c4386eSCy Schubert
146*e0c4386eSCy Schubert#Unrecognised record type tests
147*e0c4386eSCy Schubert
148*e0c4386eSCy Schubert#Test 10: Sending an unrecognised record type in TLS1.2 should fail
149*e0c4386eSCy Schubert$fatal_alert = 0;
150*e0c4386eSCy Schubert$proxy->clear();
151*e0c4386eSCy Schubert$proxy->serverflags("-tls1_2");
152*e0c4386eSCy Schubert$proxy->clientflags("-no_tls1_3");
153*e0c4386eSCy Schubert$proxy->filter(\&add_unknown_record_type);
154*e0c4386eSCy Schubert$proxy->start();
155*e0c4386eSCy Schubertok($fatal_alert, "Unrecognised record type in TLS1.2");
156*e0c4386eSCy Schubert
157*e0c4386eSCy SchubertSKIP: {
158*e0c4386eSCy Schubert    skip "TLSv1.1 disabled", 1 if disabled("tls1_1");
159*e0c4386eSCy Schubert
160*e0c4386eSCy Schubert    #Test 11: Sending an unrecognised record type in TLS1.1 should fail
161*e0c4386eSCy Schubert    $fatal_alert = 0;
162*e0c4386eSCy Schubert    $proxy->clear();
163*e0c4386eSCy Schubert    $proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
164*e0c4386eSCy Schubert    $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
165*e0c4386eSCy Schubert    $proxy->start();
166*e0c4386eSCy Schubert    ok($fatal_alert, "Unrecognised record type in TLS1.1");
167*e0c4386eSCy Schubert}
168*e0c4386eSCy Schubert
169*e0c4386eSCy Schubert#Test 12: Sending a different record version in TLS1.2 should fail
170*e0c4386eSCy Schubert$fatal_alert = 0;
171*e0c4386eSCy Schubert$proxy->clear();
172*e0c4386eSCy Schubert$proxy->clientflags("-tls1_2");
173*e0c4386eSCy Schubert$proxy->filter(\&change_version);
174*e0c4386eSCy Schubert$proxy->start();
175*e0c4386eSCy Schubertok($fatal_alert, "Changed record version in TLS1.2");
176*e0c4386eSCy Schubert
177*e0c4386eSCy Schubert#TLS1.3 specific tests
178*e0c4386eSCy SchubertSKIP: {
179*e0c4386eSCy Schubert    skip "TLSv1.3 disabled", 8
180*e0c4386eSCy Schubert        if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
181*e0c4386eSCy Schubert
182*e0c4386eSCy Schubert    #Test 13: Sending a different record version in TLS1.3 should fail
183*e0c4386eSCy Schubert    $proxy->clear();
184*e0c4386eSCy Schubert    $proxy->filter(\&change_version);
185*e0c4386eSCy Schubert    $proxy->start();
186*e0c4386eSCy Schubert    ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
187*e0c4386eSCy Schubert
188*e0c4386eSCy Schubert    #Test 14: Sending an unrecognised record type in TLS1.3 should fail
189*e0c4386eSCy Schubert    $fatal_alert = 0;
190*e0c4386eSCy Schubert    $proxy->clear();
191*e0c4386eSCy Schubert    $proxy->filter(\&add_unknown_record_type);
192*e0c4386eSCy Schubert    $proxy->start();
193*e0c4386eSCy Schubert    ok($fatal_alert, "Unrecognised record type in TLS1.3");
194*e0c4386eSCy Schubert
195*e0c4386eSCy Schubert    #Test 15: Sending an outer record type other than app data once encrypted
196*e0c4386eSCy Schubert    #should fail
197*e0c4386eSCy Schubert    $fatal_alert = 0;
198*e0c4386eSCy Schubert    $proxy->clear();
199*e0c4386eSCy Schubert    $proxy->filter(\&change_outer_record_type);
200*e0c4386eSCy Schubert    $proxy->start();
201*e0c4386eSCy Schubert    ok($fatal_alert, "Wrong outer record type in TLS1.3");
202*e0c4386eSCy Schubert
203*e0c4386eSCy Schubert    use constant {
204*e0c4386eSCy Schubert        DATA_AFTER_SERVER_HELLO => 0,
205*e0c4386eSCy Schubert        DATA_AFTER_FINISHED => 1,
206*e0c4386eSCy Schubert        DATA_AFTER_KEY_UPDATE => 2,
207*e0c4386eSCy Schubert        DATA_BETWEEN_KEY_UPDATE => 3,
208*e0c4386eSCy Schubert        NO_DATA_BETWEEN_KEY_UPDATE => 4,
209*e0c4386eSCy Schubert    };
210*e0c4386eSCy Schubert
211*e0c4386eSCy Schubert    #Test 16: Sending a ServerHello which doesn't end on a record boundary
212*e0c4386eSCy Schubert    #         should fail
213*e0c4386eSCy Schubert    $fatal_alert = 0;
214*e0c4386eSCy Schubert    $proxy->clear();
215*e0c4386eSCy Schubert    $boundary_test_type = DATA_AFTER_SERVER_HELLO;
216*e0c4386eSCy Schubert    $proxy->filter(\&not_on_record_boundary);
217*e0c4386eSCy Schubert    $proxy->start();
218*e0c4386eSCy Schubert    ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
219*e0c4386eSCy Schubert
220*e0c4386eSCy Schubert    #Test 17: Sending a Finished which doesn't end on a record boundary
221*e0c4386eSCy Schubert    #         should fail
222*e0c4386eSCy Schubert    $fatal_alert = 0;
223*e0c4386eSCy Schubert    $proxy->clear();
224*e0c4386eSCy Schubert    $boundary_test_type = DATA_AFTER_FINISHED;
225*e0c4386eSCy Schubert    $proxy->start();
226*e0c4386eSCy Schubert    ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
227*e0c4386eSCy Schubert
228*e0c4386eSCy Schubert    #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
229*e0c4386eSCy Schubert    #         should fail
230*e0c4386eSCy Schubert    $fatal_alert = 0;
231*e0c4386eSCy Schubert    $proxy->clear();
232*e0c4386eSCy Schubert    $boundary_test_type = DATA_AFTER_KEY_UPDATE;
233*e0c4386eSCy Schubert    $proxy->start();
234*e0c4386eSCy Schubert    ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
235*e0c4386eSCy Schubert
236*e0c4386eSCy Schubert    #Test 19: Sending application data in the middle of a fragmented KeyUpdate
237*e0c4386eSCy Schubert    #         should fail. Strictly speaking this is not a record boundary test
238*e0c4386eSCy Schubert    #         but we use the same filter.
239*e0c4386eSCy Schubert    $fatal_alert = 0;
240*e0c4386eSCy Schubert    $proxy->clear();
241*e0c4386eSCy Schubert    $boundary_test_type = DATA_BETWEEN_KEY_UPDATE;
242*e0c4386eSCy Schubert    $proxy->start();
243*e0c4386eSCy Schubert    ok($fatal_alert, "Data between KeyUpdate");
244*e0c4386eSCy Schubert
245*e0c4386eSCy Schubert    #Test 20: Fragmented KeyUpdate. This should succeed. Strictly speaking this
246*e0c4386eSCy Schubert    #         is not a record boundary test but we use the same filter.
247*e0c4386eSCy Schubert    $proxy->clear();
248*e0c4386eSCy Schubert    $boundary_test_type = NO_DATA_BETWEEN_KEY_UPDATE;
249*e0c4386eSCy Schubert    $proxy->start();
250*e0c4386eSCy Schubert    ok(TLSProxy::Message->success(), "No data between KeyUpdate");
251*e0c4386eSCy Schubert }
252*e0c4386eSCy Schubert
253*e0c4386eSCy Schubert
254*e0c4386eSCy Schubertsub add_empty_recs_filter
255*e0c4386eSCy Schubert{
256*e0c4386eSCy Schubert    my $proxy = shift;
257*e0c4386eSCy Schubert    my $records = $proxy->record_list;
258*e0c4386eSCy Schubert
259*e0c4386eSCy Schubert    # We're only interested in the initial ClientHello
260*e0c4386eSCy Schubert    if ($proxy->flight != 0) {
261*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
262*e0c4386eSCy Schubert        return;
263*e0c4386eSCy Schubert    }
264*e0c4386eSCy Schubert
265*e0c4386eSCy Schubert    for (my $i = 0; $i < $inject_recs_num; $i++) {
266*e0c4386eSCy Schubert        my $record = TLSProxy::Record->new(
267*e0c4386eSCy Schubert            0,
268*e0c4386eSCy Schubert            $content_type,
269*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
270*e0c4386eSCy Schubert            0,
271*e0c4386eSCy Schubert            0,
272*e0c4386eSCy Schubert            0,
273*e0c4386eSCy Schubert            0,
274*e0c4386eSCy Schubert            "",
275*e0c4386eSCy Schubert            ""
276*e0c4386eSCy Schubert        );
277*e0c4386eSCy Schubert        push @{$records}, $record;
278*e0c4386eSCy Schubert    }
279*e0c4386eSCy Schubert}
280*e0c4386eSCy Schubert
281*e0c4386eSCy Schubertsub add_frag_alert_filter
282*e0c4386eSCy Schubert{
283*e0c4386eSCy Schubert    my $proxy = shift;
284*e0c4386eSCy Schubert    my $records = $proxy->record_list;
285*e0c4386eSCy Schubert    my $byte;
286*e0c4386eSCy Schubert
287*e0c4386eSCy Schubert    # We're only interested in the initial ClientHello
288*e0c4386eSCy Schubert    if ($proxy->flight != 0) {
289*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == 10;
290*e0c4386eSCy Schubert        return;
291*e0c4386eSCy Schubert    }
292*e0c4386eSCy Schubert
293*e0c4386eSCy Schubert    # Add a zero length fragment first
294*e0c4386eSCy Schubert    #my $record = TLSProxy::Record->new(
295*e0c4386eSCy Schubert    #    0,
296*e0c4386eSCy Schubert    #    TLSProxy::Record::RT_ALERT,
297*e0c4386eSCy Schubert    #    TLSProxy::Record::VERS_TLS_1_2,
298*e0c4386eSCy Schubert    #    0,
299*e0c4386eSCy Schubert    #    0,
300*e0c4386eSCy Schubert    #    0,
301*e0c4386eSCy Schubert    #    "",
302*e0c4386eSCy Schubert    #    ""
303*e0c4386eSCy Schubert    #);
304*e0c4386eSCy Schubert    #push @{$proxy->record_list}, $record;
305*e0c4386eSCy Schubert
306*e0c4386eSCy Schubert    # Now add the alert level (Fatal) as a separate record
307*e0c4386eSCy Schubert    $byte = pack('C', TLSProxy::Message::AL_LEVEL_FATAL);
308*e0c4386eSCy Schubert    my $record = TLSProxy::Record->new(
309*e0c4386eSCy Schubert        0,
310*e0c4386eSCy Schubert        TLSProxy::Record::RT_ALERT,
311*e0c4386eSCy Schubert        TLSProxy::Record::VERS_TLS_1_2,
312*e0c4386eSCy Schubert        1,
313*e0c4386eSCy Schubert        0,
314*e0c4386eSCy Schubert        1,
315*e0c4386eSCy Schubert        1,
316*e0c4386eSCy Schubert        $byte,
317*e0c4386eSCy Schubert        $byte
318*e0c4386eSCy Schubert    );
319*e0c4386eSCy Schubert    push @{$records}, $record;
320*e0c4386eSCy Schubert
321*e0c4386eSCy Schubert    # And finally the description (Unexpected message) in a third record
322*e0c4386eSCy Schubert    $byte = pack('C', TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE);
323*e0c4386eSCy Schubert    $record = TLSProxy::Record->new(
324*e0c4386eSCy Schubert        0,
325*e0c4386eSCy Schubert        TLSProxy::Record::RT_ALERT,
326*e0c4386eSCy Schubert        TLSProxy::Record::VERS_TLS_1_2,
327*e0c4386eSCy Schubert        1,
328*e0c4386eSCy Schubert        0,
329*e0c4386eSCy Schubert        1,
330*e0c4386eSCy Schubert        1,
331*e0c4386eSCy Schubert        $byte,
332*e0c4386eSCy Schubert        $byte
333*e0c4386eSCy Schubert    );
334*e0c4386eSCy Schubert    push @{$records}, $record;
335*e0c4386eSCy Schubert}
336*e0c4386eSCy Schubert
337*e0c4386eSCy Schubertsub add_sslv2_filter
338*e0c4386eSCy Schubert{
339*e0c4386eSCy Schubert    my $proxy = shift;
340*e0c4386eSCy Schubert    my $clienthello;
341*e0c4386eSCy Schubert    my $record;
342*e0c4386eSCy Schubert
343*e0c4386eSCy Schubert    # We're only interested in the initial ClientHello
344*e0c4386eSCy Schubert    if ($proxy->flight != 0) {
345*e0c4386eSCy Schubert        return;
346*e0c4386eSCy Schubert    }
347*e0c4386eSCy Schubert
348*e0c4386eSCy Schubert    # Ditch the real ClientHello - we're going to replace it with our own
349*e0c4386eSCy Schubert    shift @{$proxy->record_list};
350*e0c4386eSCy Schubert
351*e0c4386eSCy Schubert    if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
352*e0c4386eSCy Schubert        my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
353*e0c4386eSCy Schubert                               TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
354*e0c4386eSCy Schubert        my $alertlen = length $alert;
355*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
356*e0c4386eSCy Schubert            0,
357*e0c4386eSCy Schubert            TLSProxy::Record::RT_ALERT,
358*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
359*e0c4386eSCy Schubert            $alertlen,
360*e0c4386eSCy Schubert            0,
361*e0c4386eSCy Schubert            $alertlen,
362*e0c4386eSCy Schubert            $alertlen,
363*e0c4386eSCy Schubert            $alert,
364*e0c4386eSCy Schubert            $alert
365*e0c4386eSCy Schubert        );
366*e0c4386eSCy Schubert
367*e0c4386eSCy Schubert        push @{$proxy->record_list}, $record;
368*e0c4386eSCy Schubert    }
369*e0c4386eSCy Schubert
370*e0c4386eSCy Schubert    if ($sslv2testtype == ALERT_BEFORE_SSLV2
371*e0c4386eSCy Schubert            || $sslv2testtype == TLSV1_2_IN_SSLV2
372*e0c4386eSCy Schubert            || $sslv2testtype == SSLV2_IN_SSLV2) {
373*e0c4386eSCy Schubert        # This is an SSLv2 format ClientHello
374*e0c4386eSCy Schubert        $clienthello =
375*e0c4386eSCy Schubert            pack "C44",
376*e0c4386eSCy Schubert            0x01, # ClientHello
377*e0c4386eSCy Schubert            0x03, 0x03, #TLSv1.2
378*e0c4386eSCy Schubert            0x00, 0x03, # Ciphersuites len
379*e0c4386eSCy Schubert            0x00, 0x00, # Session id len
380*e0c4386eSCy Schubert            0x00, 0x20, # Challenge len
381*e0c4386eSCy Schubert            0x00, 0x00, 0x2f, #AES128-SHA
382*e0c4386eSCy Schubert            0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
383*e0c4386eSCy Schubert            0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
384*e0c4386eSCy Schubert            0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
385*e0c4386eSCy Schubert
386*e0c4386eSCy Schubert        if ($sslv2testtype == SSLV2_IN_SSLV2) {
387*e0c4386eSCy Schubert            # Set the version to "real" SSLv2
388*e0c4386eSCy Schubert            vec($clienthello, 1, 8) = 0x00;
389*e0c4386eSCy Schubert            vec($clienthello, 2, 8) = 0x02;
390*e0c4386eSCy Schubert        }
391*e0c4386eSCy Schubert
392*e0c4386eSCy Schubert        my $chlen = length $clienthello;
393*e0c4386eSCy Schubert
394*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
395*e0c4386eSCy Schubert            0,
396*e0c4386eSCy Schubert            TLSProxy::Record::RT_HANDSHAKE,
397*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
398*e0c4386eSCy Schubert            $chlen,
399*e0c4386eSCy Schubert            1, #SSLv2
400*e0c4386eSCy Schubert            $chlen,
401*e0c4386eSCy Schubert            $chlen,
402*e0c4386eSCy Schubert            $clienthello,
403*e0c4386eSCy Schubert            $clienthello
404*e0c4386eSCy Schubert        );
405*e0c4386eSCy Schubert
406*e0c4386eSCy Schubert        push @{$proxy->record_list}, $record;
407*e0c4386eSCy Schubert    } else {
408*e0c4386eSCy Schubert        # For this test we're using a real TLS ClientHello
409*e0c4386eSCy Schubert        $clienthello =
410*e0c4386eSCy Schubert            pack "C49",
411*e0c4386eSCy Schubert            0x01, # ClientHello
412*e0c4386eSCy Schubert            0x00, 0x00, 0x2D, # Message length
413*e0c4386eSCy Schubert            0x03, 0x03, # TLSv1.2
414*e0c4386eSCy Schubert            0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
415*e0c4386eSCy Schubert            0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
416*e0c4386eSCy Schubert            0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
417*e0c4386eSCy Schubert            0x00, # Session id len
418*e0c4386eSCy Schubert            0x00, 0x04, # Ciphersuites len
419*e0c4386eSCy Schubert            0x00, 0x2f, # AES128-SHA
420*e0c4386eSCy Schubert            0x00, 0xff, # Empty reneg info SCSV
421*e0c4386eSCy Schubert            0x01, # Compression methods len
422*e0c4386eSCy Schubert            0x00, # Null compression
423*e0c4386eSCy Schubert            0x00, 0x00; # Extensions len
424*e0c4386eSCy Schubert
425*e0c4386eSCy Schubert        # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
426*e0c4386eSCy Schubert        # We deliberately split the second record prior to the Challenge/Random
427*e0c4386eSCy Schubert        # and set the first byte of the random to 1. This makes the second SSLv2
428*e0c4386eSCy Schubert        # record look like an SSLv2 ClientHello
429*e0c4386eSCy Schubert        my $frag1 = substr $clienthello, 0, 6;
430*e0c4386eSCy Schubert        my $frag2 = substr $clienthello, 6, 32;
431*e0c4386eSCy Schubert        my $frag3 = substr $clienthello, 38;
432*e0c4386eSCy Schubert
433*e0c4386eSCy Schubert        my $fraglen = length $frag1;
434*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
435*e0c4386eSCy Schubert            0,
436*e0c4386eSCy Schubert            TLSProxy::Record::RT_HANDSHAKE,
437*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
438*e0c4386eSCy Schubert            $fraglen,
439*e0c4386eSCy Schubert            0,
440*e0c4386eSCy Schubert            $fraglen,
441*e0c4386eSCy Schubert            $fraglen,
442*e0c4386eSCy Schubert            $frag1,
443*e0c4386eSCy Schubert            $frag1
444*e0c4386eSCy Schubert        );
445*e0c4386eSCy Schubert        push @{$proxy->record_list}, $record;
446*e0c4386eSCy Schubert
447*e0c4386eSCy Schubert        $fraglen = length $frag2;
448*e0c4386eSCy Schubert        my $recvers;
449*e0c4386eSCy Schubert        if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
450*e0c4386eSCy Schubert            $recvers = 1;
451*e0c4386eSCy Schubert        } else {
452*e0c4386eSCy Schubert            $recvers = 0;
453*e0c4386eSCy Schubert        }
454*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
455*e0c4386eSCy Schubert            0,
456*e0c4386eSCy Schubert            TLSProxy::Record::RT_HANDSHAKE,
457*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
458*e0c4386eSCy Schubert            $fraglen,
459*e0c4386eSCy Schubert            $recvers,
460*e0c4386eSCy Schubert            $fraglen,
461*e0c4386eSCy Schubert            $fraglen,
462*e0c4386eSCy Schubert            $frag2,
463*e0c4386eSCy Schubert            $frag2
464*e0c4386eSCy Schubert        );
465*e0c4386eSCy Schubert        push @{$proxy->record_list}, $record;
466*e0c4386eSCy Schubert
467*e0c4386eSCy Schubert        $fraglen = length $frag3;
468*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
469*e0c4386eSCy Schubert            0,
470*e0c4386eSCy Schubert            TLSProxy::Record::RT_HANDSHAKE,
471*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
472*e0c4386eSCy Schubert            $fraglen,
473*e0c4386eSCy Schubert            0,
474*e0c4386eSCy Schubert            $fraglen,
475*e0c4386eSCy Schubert            $fraglen,
476*e0c4386eSCy Schubert            $frag3,
477*e0c4386eSCy Schubert            $frag3
478*e0c4386eSCy Schubert        );
479*e0c4386eSCy Schubert        push @{$proxy->record_list}, $record;
480*e0c4386eSCy Schubert    }
481*e0c4386eSCy Schubert
482*e0c4386eSCy Schubert}
483*e0c4386eSCy Schubert
484*e0c4386eSCy Schubertsub add_unknown_record_type
485*e0c4386eSCy Schubert{
486*e0c4386eSCy Schubert    my $proxy = shift;
487*e0c4386eSCy Schubert    my $records = $proxy->record_list;
488*e0c4386eSCy Schubert    state $added_record;
489*e0c4386eSCy Schubert
490*e0c4386eSCy Schubert    # We'll change a record after the initial version neg has taken place
491*e0c4386eSCy Schubert    if ($proxy->flight == 0) {
492*e0c4386eSCy Schubert        $added_record = 0;
493*e0c4386eSCy Schubert        return;
494*e0c4386eSCy Schubert    } elsif ($proxy->flight != 1 || $added_record) {
495*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
496*e0c4386eSCy Schubert        return;
497*e0c4386eSCy Schubert    }
498*e0c4386eSCy Schubert
499*e0c4386eSCy Schubert    my $record = TLSProxy::Record->new(
500*e0c4386eSCy Schubert        1,
501*e0c4386eSCy Schubert        TLSProxy::Record::RT_UNKNOWN,
502*e0c4386eSCy Schubert        @{$records}[-1]->version(),
503*e0c4386eSCy Schubert        1,
504*e0c4386eSCy Schubert        0,
505*e0c4386eSCy Schubert        1,
506*e0c4386eSCy Schubert        1,
507*e0c4386eSCy Schubert        "X",
508*e0c4386eSCy Schubert        "X"
509*e0c4386eSCy Schubert    );
510*e0c4386eSCy Schubert
511*e0c4386eSCy Schubert    #Find ServerHello record and insert after that
512*e0c4386eSCy Schubert    my $i;
513*e0c4386eSCy Schubert    for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
514*e0c4386eSCy Schubert        next;
515*e0c4386eSCy Schubert    }
516*e0c4386eSCy Schubert    $i++;
517*e0c4386eSCy Schubert
518*e0c4386eSCy Schubert    splice @{$proxy->record_list}, $i, 0, $record;
519*e0c4386eSCy Schubert    $added_record = 1;
520*e0c4386eSCy Schubert}
521*e0c4386eSCy Schubert
522*e0c4386eSCy Schubertsub change_version
523*e0c4386eSCy Schubert{
524*e0c4386eSCy Schubert    my $proxy = shift;
525*e0c4386eSCy Schubert    my $records = $proxy->record_list;
526*e0c4386eSCy Schubert
527*e0c4386eSCy Schubert    # We'll change a version after the initial version neg has taken place
528*e0c4386eSCy Schubert    if ($proxy->flight != 1) {
529*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
530*e0c4386eSCy Schubert        return;
531*e0c4386eSCy Schubert    }
532*e0c4386eSCy Schubert
533*e0c4386eSCy Schubert    if ($#{$records} > 1) {
534*e0c4386eSCy Schubert        # ... typically in ServerHelloDone
535*e0c4386eSCy Schubert        @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
536*e0c4386eSCy Schubert    }
537*e0c4386eSCy Schubert}
538*e0c4386eSCy Schubert
539*e0c4386eSCy Schubertsub change_outer_record_type
540*e0c4386eSCy Schubert{
541*e0c4386eSCy Schubert    my $proxy = shift;
542*e0c4386eSCy Schubert    my $records = $proxy->record_list;
543*e0c4386eSCy Schubert
544*e0c4386eSCy Schubert    # We'll change a record after the initial version neg has taken place
545*e0c4386eSCy Schubert    if ($proxy->flight != 1) {
546*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
547*e0c4386eSCy Schubert        return;
548*e0c4386eSCy Schubert    }
549*e0c4386eSCy Schubert
550*e0c4386eSCy Schubert    # Find CCS record and change record after that
551*e0c4386eSCy Schubert    my $i = 0;
552*e0c4386eSCy Schubert    foreach my $record (@{$records}) {
553*e0c4386eSCy Schubert        last if $record->content_type == TLSProxy::Record::RT_CCS;
554*e0c4386eSCy Schubert        $i++;
555*e0c4386eSCy Schubert    }
556*e0c4386eSCy Schubert    if (defined(${$records}[++$i])) {
557*e0c4386eSCy Schubert        ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
558*e0c4386eSCy Schubert    }
559*e0c4386eSCy Schubert}
560*e0c4386eSCy Schubert
561*e0c4386eSCy Schubertsub not_on_record_boundary
562*e0c4386eSCy Schubert{
563*e0c4386eSCy Schubert    my $proxy = shift;
564*e0c4386eSCy Schubert    my $records = $proxy->record_list;
565*e0c4386eSCy Schubert    my $data;
566*e0c4386eSCy Schubert
567*e0c4386eSCy Schubert    #Find server's first flight
568*e0c4386eSCy Schubert    if ($proxy->flight != 1) {
569*e0c4386eSCy Schubert        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
570*e0c4386eSCy Schubert        return;
571*e0c4386eSCy Schubert    }
572*e0c4386eSCy Schubert
573*e0c4386eSCy Schubert    if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
574*e0c4386eSCy Schubert        #Merge the ServerHello and EncryptedExtensions records into one
575*e0c4386eSCy Schubert        my $i = 0;
576*e0c4386eSCy Schubert        foreach my $record (@{$records}) {
577*e0c4386eSCy Schubert            if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
578*e0c4386eSCy Schubert                $record->{sent} = 1;    # pretend it's sent already
579*e0c4386eSCy Schubert                last;
580*e0c4386eSCy Schubert            }
581*e0c4386eSCy Schubert            $i++;
582*e0c4386eSCy Schubert        }
583*e0c4386eSCy Schubert
584*e0c4386eSCy Schubert        if (defined(${$records}[$i+1])) {
585*e0c4386eSCy Schubert            $data = ${$records}[$i]->data();
586*e0c4386eSCy Schubert            $data .= ${$records}[$i+1]->decrypt_data();
587*e0c4386eSCy Schubert            ${$records}[$i+1]->data($data);
588*e0c4386eSCy Schubert            ${$records}[$i+1]->len(length $data);
589*e0c4386eSCy Schubert
590*e0c4386eSCy Schubert            #Delete the old ServerHello record
591*e0c4386eSCy Schubert            splice @{$records}, $i, 1;
592*e0c4386eSCy Schubert        }
593*e0c4386eSCy Schubert    } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
594*e0c4386eSCy Schubert        return if @{$proxy->{message_list}}[-1]->{mt}
595*e0c4386eSCy Schubert                  != TLSProxy::Message::MT_FINISHED;
596*e0c4386eSCy Schubert
597*e0c4386eSCy Schubert        my $last_record = @{$records}[-1];
598*e0c4386eSCy Schubert        $data = $last_record->decrypt_data;
599*e0c4386eSCy Schubert
600*e0c4386eSCy Schubert        #Add a KeyUpdate message onto the end of the Finished record
601*e0c4386eSCy Schubert        my $keyupdate = pack "C5",
602*e0c4386eSCy Schubert            0x18, # KeyUpdate
603*e0c4386eSCy Schubert            0x00, 0x00, 0x01, # Message length
604*e0c4386eSCy Schubert            0x00; # Update not requested
605*e0c4386eSCy Schubert
606*e0c4386eSCy Schubert        $data .= $keyupdate;
607*e0c4386eSCy Schubert
608*e0c4386eSCy Schubert        #Add content type and tag
609*e0c4386eSCy Schubert        $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
610*e0c4386eSCy Schubert
611*e0c4386eSCy Schubert        #Update the record
612*e0c4386eSCy Schubert        $last_record->data($data);
613*e0c4386eSCy Schubert        $last_record->len(length $data);
614*e0c4386eSCy Schubert    } elsif ($boundary_test_type == DATA_AFTER_KEY_UPDATE) {
615*e0c4386eSCy Schubert        return if @{$proxy->{message_list}}[-1]->{mt}
616*e0c4386eSCy Schubert                  != TLSProxy::Message::MT_FINISHED;
617*e0c4386eSCy Schubert
618*e0c4386eSCy Schubert        #KeyUpdates must end on a record boundary
619*e0c4386eSCy Schubert
620*e0c4386eSCy Schubert        my $record = TLSProxy::Record->new(
621*e0c4386eSCy Schubert            1,
622*e0c4386eSCy Schubert            TLSProxy::Record::RT_APPLICATION_DATA,
623*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
624*e0c4386eSCy Schubert            0,
625*e0c4386eSCy Schubert            0,
626*e0c4386eSCy Schubert            0,
627*e0c4386eSCy Schubert            0,
628*e0c4386eSCy Schubert            "",
629*e0c4386eSCy Schubert            ""
630*e0c4386eSCy Schubert        );
631*e0c4386eSCy Schubert
632*e0c4386eSCy Schubert        #Add two KeyUpdate messages into a single record
633*e0c4386eSCy Schubert        my $keyupdate = pack "C5",
634*e0c4386eSCy Schubert            0x18, # KeyUpdate
635*e0c4386eSCy Schubert            0x00, 0x00, 0x01, # Message length
636*e0c4386eSCy Schubert            0x00; # Update not requested
637*e0c4386eSCy Schubert
638*e0c4386eSCy Schubert        $data = $keyupdate.$keyupdate;
639*e0c4386eSCy Schubert
640*e0c4386eSCy Schubert        #Add content type and tag
641*e0c4386eSCy Schubert        $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
642*e0c4386eSCy Schubert
643*e0c4386eSCy Schubert        $record->data($data);
644*e0c4386eSCy Schubert        $record->len(length $data);
645*e0c4386eSCy Schubert        push @{$records}, $record;
646*e0c4386eSCy Schubert    } else {
647*e0c4386eSCy Schubert        return if @{$proxy->{message_list}}[-1]->{mt}
648*e0c4386eSCy Schubert                  != TLSProxy::Message::MT_FINISHED;
649*e0c4386eSCy Schubert
650*e0c4386eSCy Schubert        my $record = TLSProxy::Record->new(
651*e0c4386eSCy Schubert            1,
652*e0c4386eSCy Schubert            TLSProxy::Record::RT_APPLICATION_DATA,
653*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
654*e0c4386eSCy Schubert            0,
655*e0c4386eSCy Schubert            0,
656*e0c4386eSCy Schubert            0,
657*e0c4386eSCy Schubert            0,
658*e0c4386eSCy Schubert            "",
659*e0c4386eSCy Schubert            ""
660*e0c4386eSCy Schubert        );
661*e0c4386eSCy Schubert
662*e0c4386eSCy Schubert        #Add a partial KeyUpdate message into the record
663*e0c4386eSCy Schubert        $data = pack "C1",
664*e0c4386eSCy Schubert            0x18; # KeyUpdate message type. Omit the rest of the message header
665*e0c4386eSCy Schubert
666*e0c4386eSCy Schubert        #Add content type and tag
667*e0c4386eSCy Schubert        $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
668*e0c4386eSCy Schubert
669*e0c4386eSCy Schubert        $record->data($data);
670*e0c4386eSCy Schubert        $record->len(length $data);
671*e0c4386eSCy Schubert        push @{$records}, $record;
672*e0c4386eSCy Schubert
673*e0c4386eSCy Schubert        if ($boundary_test_type == DATA_BETWEEN_KEY_UPDATE) {
674*e0c4386eSCy Schubert            #Now add an app data record
675*e0c4386eSCy Schubert            $record = TLSProxy::Record->new(
676*e0c4386eSCy Schubert                1,
677*e0c4386eSCy Schubert                TLSProxy::Record::RT_APPLICATION_DATA,
678*e0c4386eSCy Schubert                TLSProxy::Record::VERS_TLS_1_2,
679*e0c4386eSCy Schubert                0,
680*e0c4386eSCy Schubert                0,
681*e0c4386eSCy Schubert                0,
682*e0c4386eSCy Schubert                0,
683*e0c4386eSCy Schubert                "",
684*e0c4386eSCy Schubert                ""
685*e0c4386eSCy Schubert            );
686*e0c4386eSCy Schubert
687*e0c4386eSCy Schubert            #Add an empty app data record (just content type and tag)
688*e0c4386eSCy Schubert            $data = pack("C", TLSProxy::Record::RT_APPLICATION_DATA).("\0"x16);
689*e0c4386eSCy Schubert
690*e0c4386eSCy Schubert            $record->data($data);
691*e0c4386eSCy Schubert            $record->len(length $data);
692*e0c4386eSCy Schubert            push @{$records}, $record;
693*e0c4386eSCy Schubert        }
694*e0c4386eSCy Schubert
695*e0c4386eSCy Schubert        #Now add the rest of the KeyUpdate message
696*e0c4386eSCy Schubert        $record = TLSProxy::Record->new(
697*e0c4386eSCy Schubert            1,
698*e0c4386eSCy Schubert            TLSProxy::Record::RT_APPLICATION_DATA,
699*e0c4386eSCy Schubert            TLSProxy::Record::VERS_TLS_1_2,
700*e0c4386eSCy Schubert            0,
701*e0c4386eSCy Schubert            0,
702*e0c4386eSCy Schubert            0,
703*e0c4386eSCy Schubert            0,
704*e0c4386eSCy Schubert            "",
705*e0c4386eSCy Schubert            ""
706*e0c4386eSCy Schubert        );
707*e0c4386eSCy Schubert
708*e0c4386eSCy Schubert        #Add the last 4 bytes of the KeyUpdate record
709*e0c4386eSCy Schubert        $data = pack "C4",
710*e0c4386eSCy Schubert            0x00, 0x00, 0x01, # Message length
711*e0c4386eSCy Schubert            0x00; # Update not requested
712*e0c4386eSCy Schubert
713*e0c4386eSCy Schubert        #Add content type and tag
714*e0c4386eSCy Schubert        $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
715*e0c4386eSCy Schubert
716*e0c4386eSCy Schubert        $record->data($data);
717*e0c4386eSCy Schubert        $record->len(length $data);
718*e0c4386eSCy Schubert        push @{$records}, $record;
719*e0c4386eSCy Schubert
720*e0c4386eSCy Schubert    }
721*e0c4386eSCy Schubert}
722