Add tests for new extension code
[openssl.git] / test / recipes / 70-test_tls13messages.t
1 #! /usr/bin/env perl
2 # Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 use strict;
10 use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
11 use OpenSSL::Test::Utils;
12 use File::Temp qw(tempfile);
13 use TLSProxy::Proxy;
14 my $test_name = "test_tls13messages";
15 setup($test_name);
16
17 plan skip_all => "TLSProxy isn't usable on $^O"
18     if $^O =~ /^(VMS|MSWin32)$/;
19
20 plan skip_all => "$test_name needs the dynamic engine feature enabled"
21     if disabled("engine") || disabled("dynamic-engine");
22
23 plan skip_all => "$test_name needs the sock feature enabled"
24     if disabled("sock");
25
26 plan skip_all => "$test_name needs TLSv1.3 enabled"
27     if disabled("tls1_3");
28
29 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
30 $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
31
32 use constant {
33     DEFAULT_HANDSHAKE => 1,
34     OCSP_HANDSHAKE => 2,
35     RESUME_HANDSHAKE => 4,
36     CLIENT_AUTH_HANDSHAKE => 8,
37     ALL_HANDSHAKES => 15
38 };
39
40 use constant {
41     DEFAULT_EXTENSIONS => 0x00000001,
42     SERVER_NAME_CLI_EXTENSION => 0x00000002,
43     SERVER_NAME_SRV_EXTENSION => 0x00000004,
44     STATUS_REQUEST_CLI_EXTENSION => 0x00000008,
45     STATUS_REQUEST_SRV_EXTENSION => 0x00000010,
46     ALPN_CLI_EXTENSION => 0x00000020,
47     ALPN_SRV_EXTENSION => 0x00000040,
48     SCT_CLI_EXTENSION => 0x00000080
49 };
50
51 my @handmessages = (
52     [TLSProxy::Message::MT_CLIENT_HELLO, ALL_HANDSHAKES],
53     [TLSProxy::Message::MT_SERVER_HELLO, ALL_HANDSHAKES],
54     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, ALL_HANDSHAKES],
55     [TLSProxy::Message::MT_CERTIFICATE_REQUEST, CLIENT_AUTH_HANDSHAKE],
56     [TLSProxy::Message::MT_CERTIFICATE, ALL_HANDSHAKES & ~RESUME_HANDSHAKE],
57     [TLSProxy::Message::MT_CERTIFICATE_STATUS, OCSP_HANDSHAKE],
58     [TLSProxy::Message::MT_FINISHED, ALL_HANDSHAKES],
59     [TLSProxy::Message::MT_CERTIFICATE, CLIENT_AUTH_HANDSHAKE],
60     [TLSProxy::Message::MT_CERTIFICATE_VERIFY, CLIENT_AUTH_HANDSHAKE],
61     [TLSProxy::Message::MT_FINISHED, ALL_HANDSHAKES],
62     [0, 0]
63 );
64
65 my @extensions = (
66     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, SERVER_NAME_CLI_EXTENSION],
67     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST, STATUS_REQUEST_CLI_EXTENSION],
68     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS, DEFAULT_EXTENSIONS],
69     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS, DEFAULT_EXTENSIONS],
70     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS, DEFAULT_EXTENSIONS],
71     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN, ALPN_CLI_EXTENSION],
72     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT, SCT_CLI_EXTENSION],
73     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC, DEFAULT_EXTENSIONS],
74     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET, DEFAULT_EXTENSIONS],
75     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET, DEFAULT_EXTENSIONS],
76     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE, DEFAULT_EXTENSIONS],
77     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, DEFAULT_EXTENSIONS],
78
79     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, DEFAULT_EXTENSIONS],
80
81     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SERVER_NAME, SERVER_NAME_SRV_EXTENSION],
82     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_STATUS_REQUEST, STATUS_REQUEST_SRV_EXTENSION],
83     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_ALPN, ALPN_SRV_EXTENSION],
84     [0,0,0]
85 );
86
87 my $proxy = TLSProxy::Proxy->new(
88     undef,
89     cmdstr(app(["openssl"]), display => 1),
90     srctop_file("apps", "server.pem"),
91     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
92 );
93
94 sub checkmessages($$$);
95
96 #Test 1: Check we get all the right messages for a default handshake
97 (undef, my $session) = tempfile();
98 #$proxy->serverconnects(2);
99 $proxy->clientflags("-sess_out ".$session);
100 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
101 plan tests => 12;
102 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS, "Default handshake test");
103
104 #TODO(TLS1.3): Test temporarily disabled until we implement TLS1.3 resumption
105 #Test 2: Resumption handshake
106 #$proxy->clearClient();
107 #$proxy->clientflags("-sess_in ".$session);
108 #$proxy->clientstart();
109 #checkmessages(RESUME_HANDSHAKE, "Resumption handshake test");
110 unlink $session;
111
112 #Test 3: A status_request handshake (client request only)
113 $proxy->clear();
114 $proxy->clientflags("-status");
115 $proxy->start();
116 checkmessages(DEFAULT_HANDSHAKE,
117               DEFAULT_EXTENSIONS | STATUS_REQUEST_CLI_EXTENSION,
118               "status_request handshake test (client)");
119
120 #Test 4: A status_request handshake (server support only)
121 $proxy->clear();
122 $proxy->serverflags("-status_file "
123                     .srctop_file("test", "recipes", "ocsp-response.der"));
124 $proxy->start();
125 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
126               "status_request handshake test (server)");
127
128 #Test 5: A status_request handshake (client and server)
129 #TODO(TLS1.3): TLS1.3 doesn't actually have CertificateStatus messages. This is
130 #a temporary test until such time as we do proper TLS1.3 style certificate
131 #status
132 $proxy->clear();
133 $proxy->clientflags("-status");
134 $proxy->serverflags("-status_file "
135                     .srctop_file("test", "recipes", "ocsp-response.der"));
136 $proxy->start();
137 checkmessages(OCSP_HANDSHAKE,
138               DEFAULT_EXTENSIONS | STATUS_REQUEST_CLI_EXTENSION
139               | STATUS_REQUEST_SRV_EXTENSION,
140               "status_request handshake test");
141
142 #Test 6: A client auth handshake
143 $proxy->clear();
144 $proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
145 $proxy->serverflags("-Verify 5");
146 $proxy->start();
147 checkmessages(CLIENT_AUTH_HANDSHAKE, DEFAULT_EXTENSIONS,
148               "Client auth handshake test");
149
150 #Test 7: Server name handshake (client request only)
151 $proxy->clear();
152 $proxy->clientflags("-servername testhost");
153 $proxy->start();
154 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS | SERVER_NAME_CLI_EXTENSION,
155               "Server name handshake test (client)");
156
157 #Test 8: Server name handshake (server support only)
158 $proxy->clear();
159 $proxy->serverflags("-servername testhost");
160 $proxy->start();
161 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
162               "Server name handshake test (server)");
163
164 #Test 9: Server name handshake (client and server)
165 $proxy->clear();
166 $proxy->clientflags("-servername testhost");
167 $proxy->serverflags("-servername testhost");
168 $proxy->start();
169 checkmessages(DEFAULT_HANDSHAKE,
170               DEFAULT_EXTENSIONS | SERVER_NAME_CLI_EXTENSION
171               | SERVER_NAME_SRV_EXTENSION,
172               "Server name handshake test");
173
174 #Test 10: ALPN handshake (client request only)
175 $proxy->clear();
176 $proxy->clientflags("-alpn test");
177 $proxy->start();
178 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS | ALPN_CLI_EXTENSION,
179               "ALPN handshake test (client)");
180
181 #Test 11: ALPN handshake (server support only)
182 $proxy->clear();
183 $proxy->serverflags("-alpn test");
184 $proxy->start();
185 checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
186               "ALPN handshake test (server)");
187               
188 #Test 12: ALPN handshake (client and server)
189 $proxy->clear();
190 $proxy->clientflags("-alpn test");
191 $proxy->serverflags("-alpn test");
192 $proxy->start();
193 checkmessages(DEFAULT_HANDSHAKE,
194               DEFAULT_EXTENSIONS | ALPN_CLI_EXTENSION | ALPN_SRV_EXTENSION,
195               "ALPN handshake test");
196
197 #Test 13: SCT handshake (client request only)
198 #TODO(TLS1.3): This only checks that the client side extension appears. The
199 #SCT extension is unusual in that we have no built-in server side implementation
200 #The server side implementation can nomrally be added using the custom
201 #extensions framework (e.g. by using the "-serverinfo" s_server option). However
202 #currently we only support <= TLS1.2 for custom extensions because the existing
203 #framework and API has no knowledge of the TLS1.3 messages
204 $proxy->clear();
205 #Note: -ct also sends status_request
206 $proxy->clientflags("-ct");
207 $proxy->serverflags("-status_file "
208                     .srctop_file("test", "recipes", "ocsp-response.der"));
209 $proxy->start();
210 checkmessages(OCSP_HANDSHAKE,
211               DEFAULT_EXTENSIONS | SCT_CLI_EXTENSION
212               | STATUS_REQUEST_CLI_EXTENSION | STATUS_REQUEST_SRV_EXTENSION,
213               "SCT handshake test");
214
215 sub checkmessages($$$)
216 {
217     my ($handtype, $exttype, $testname) = @_;
218
219     subtest $testname => sub {
220         my $loop = 0;
221         my $numtests;
222         my $extcount;
223
224         #First count the number of tests
225         for ($numtests = 1; $handmessages[$loop][1] != 0; $loop++) {
226             $numtests++ if (($handmessages[$loop][1] & $handtype) != 0);
227         }
228
229         #Add number of extensions we check plus 3 for the number of messages
230         #that contain extensions
231         $numtests += $#extensions + 3;
232
233         plan tests => $numtests;
234
235         $loop = 0;
236         foreach my $message (@{$proxy->message_list}) {
237             for (; $handmessages[$loop][1] != 0
238                    && ($handmessages[$loop][1] & $handtype) == 0; $loop++) {
239                 next;
240             }
241             ok($handmessages[$loop][1] != 0
242                && $message->mt == $handmessages[$loop][0],
243                "Message type check. Got ".$message->mt
244                .", expected ".$handmessages[$loop][0]);
245             $loop++;
246
247
248             next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
249                     && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
250                     && $message->mt() !=
251                        TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS);
252              #Now check that we saw the extensions we expected
253              my $msgexts = $message->extension_data();
254              for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0;
255                                 $extloop++) {
256                 next if ($message->mt() != $extensions[$extloop][0]);
257                 ok (($extensions[$extloop][2] & $exttype) == 0
258                       || defined ($msgexts->{$extensions[$extloop][1]}),
259                     "Extension presence check (Message: ".$message->mt()
260                     ." Extension: ".($extensions[$extloop][2] & $exttype).", "
261                     .$extloop.")");
262                 $extcount++ if (($extensions[$extloop][2] & $exttype) != 0);
263              }
264             ok($extcount == keys %$msgexts, "Extensions count mismatch ("
265                                             .$extcount.", ".(keys %$msgexts)
266                                             .")");
267         }
268         ok($handmessages[$loop][1] == 0, "All expected messages processed");
269     }
270 }