]>
Commit | Line | Data |
---|---|---|
6fc1748e | 1 | /* |
72a7a702 | 2 | * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. |
6fc1748e MC |
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 | ||
6c529877 | 10 | #include <string.h> |
6fc1748e MC |
11 | #include <openssl/bio.h> |
12 | #include <openssl/crypto.h> | |
13 | #include <openssl/ssl.h> | |
14 | #include <openssl/err.h> | |
15 | ||
16 | #include "ssltestlib.h" | |
17 | #include "testutil.h" | |
18 | ||
19 | static char *cert = NULL; | |
20 | static char *privkey = NULL; | |
fa4b82cc | 21 | static unsigned int timer_cb_count; |
6fc1748e | 22 | |
ac9fc67a MC |
23 | #define NUM_TESTS 2 |
24 | ||
6fc1748e MC |
25 | |
26 | #define DUMMY_CERT_STATUS_LEN 12 | |
27 | ||
52a03d2a | 28 | static unsigned char certstatus[] = { |
6fc1748e MC |
29 | SSL3_RT_HANDSHAKE, /* Content type */ |
30 | 0xfe, 0xfd, /* Record version */ | |
31 | 0, 1, /* Epoch */ | |
32 | 0, 0, 0, 0, 0, 0x0f, /* Record sequence number */ | |
33 | 0, DTLS1_HM_HEADER_LENGTH + DUMMY_CERT_STATUS_LEN - 2, | |
34 | SSL3_MT_CERTIFICATE_STATUS, /* Cert Status handshake message type */ | |
35 | 0, 0, DUMMY_CERT_STATUS_LEN, /* Message len */ | |
36 | 0, 5, /* Message sequence */ | |
37 | 0, 0, 0, /* Fragment offset */ | |
38 | 0, 0, DUMMY_CERT_STATUS_LEN - 2, /* Fragment len */ | |
39 | 0x80, 0x80, 0x80, 0x80, 0x80, | |
40 | 0x80, 0x80, 0x80, 0x80, 0x80 /* Dummy data */ | |
41 | }; | |
42 | ||
ac9fc67a MC |
43 | #define RECORD_SEQUENCE 10 |
44 | ||
fa4b82cc AH |
45 | static unsigned int timer_cb(SSL *s, unsigned int timer_us) |
46 | { | |
47 | ++timer_cb_count; | |
48 | ||
49 | if (timer_us == 0) | |
61e96557 | 50 | return 50000; |
fa4b82cc AH |
51 | else |
52 | return 2 * timer_us; | |
53 | } | |
54 | ||
ac9fc67a | 55 | static int test_dtls_unprocessed(int testidx) |
6fc1748e MC |
56 | { |
57 | SSL_CTX *sctx = NULL, *cctx = NULL; | |
58 | SSL *serverssl1 = NULL, *clientssl1 = NULL; | |
59 | BIO *c_to_s_fbio, *c_to_s_mempacket; | |
60 | int testresult = 0; | |
61 | ||
fa4b82cc AH |
62 | timer_cb_count = 0; |
63 | ||
745dec3a | 64 | if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), |
7d7f6834 RL |
65 | DTLS_client_method(), |
66 | DTLS1_VERSION, DTLS_MAX_VERSION, | |
67 | &sctx, &cctx, cert, privkey))) | |
6fc1748e | 68 | return 0; |
6fc1748e | 69 | |
745dec3a P |
70 | if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES128-SHA"))) |
71 | goto end; | |
6fc1748e MC |
72 | |
73 | c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); | |
745dec3a | 74 | if (!TEST_ptr(c_to_s_fbio)) |
6fc1748e | 75 | goto end; |
6fc1748e MC |
76 | |
77 | /* BIO is freed by create_ssl_connection on error */ | |
745dec3a P |
78 | if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl1, &clientssl1, |
79 | NULL, c_to_s_fbio))) | |
6fc1748e | 80 | goto end; |
6fc1748e | 81 | |
fa4b82cc AH |
82 | DTLS_set_timer_cb(clientssl1, timer_cb); |
83 | ||
ac9fc67a MC |
84 | if (testidx == 1) |
85 | certstatus[RECORD_SEQUENCE] = 0xff; | |
86 | ||
6fc1748e | 87 | /* |
ac9fc67a MC |
88 | * Inject a dummy record from the next epoch. In test 0, this should never |
89 | * get used because the message sequence number is too big. In test 1 we set | |
f9ad0abb | 90 | * the record sequence number to be way off in the future. |
6fc1748e MC |
91 | */ |
92 | c_to_s_mempacket = SSL_get_wbio(clientssl1); | |
93 | c_to_s_mempacket = BIO_next(c_to_s_mempacket); | |
94 | mempacket_test_inject(c_to_s_mempacket, (char *)certstatus, | |
95 | sizeof(certstatus), 1, INJECT_PACKET_IGNORE_REC_SEQ); | |
96 | ||
f9ad0abb MC |
97 | /* |
98 | * Create the connection. We use "create_bare_ssl_connection" here so that | |
99 | * we can force the connection to not do "SSL_read" once partly conencted. | |
100 | * We don't want to accidentally read the dummy records we injected because | |
101 | * they will fail to decrypt. | |
102 | */ | |
103 | if (!TEST_true(create_bare_ssl_connection(serverssl1, clientssl1, | |
104 | SSL_ERROR_NONE, 0))) | |
6fc1748e | 105 | goto end; |
6fc1748e | 106 | |
fa4b82cc AH |
107 | if (timer_cb_count == 0) { |
108 | printf("timer_callback was not called.\n"); | |
109 | goto end; | |
110 | } | |
111 | ||
6fc1748e MC |
112 | testresult = 1; |
113 | end: | |
114 | SSL_free(serverssl1); | |
115 | SSL_free(clientssl1); | |
116 | SSL_CTX_free(sctx); | |
117 | SSL_CTX_free(cctx); | |
118 | ||
119 | return testresult; | |
120 | } | |
121 | ||
61e96557 MC |
122 | #define CLI_TO_SRV_EPOCH_0_RECS 3 |
123 | #define CLI_TO_SRV_EPOCH_1_RECS 1 | |
1aac20f5 MC |
124 | #if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH) |
125 | # define SRV_TO_CLI_EPOCH_0_RECS 12 | |
126 | #else | |
127 | /* | |
128 | * In this case we have no ServerKeyExchange message, because we don't have | |
129 | * ECDHE or DHE. When it is present it gets fragmented into 3 records in this | |
130 | * test. | |
131 | */ | |
132 | # define SRV_TO_CLI_EPOCH_0_RECS 9 | |
133 | #endif | |
61e96557 MC |
134 | #define SRV_TO_CLI_EPOCH_1_RECS 1 |
135 | #define TOTAL_FULL_HAND_RECORDS \ | |
136 | (CLI_TO_SRV_EPOCH_0_RECS + CLI_TO_SRV_EPOCH_1_RECS + \ | |
137 | SRV_TO_CLI_EPOCH_0_RECS + SRV_TO_CLI_EPOCH_1_RECS) | |
138 | ||
139 | #define CLI_TO_SRV_RESUME_EPOCH_0_RECS 3 | |
140 | #define CLI_TO_SRV_RESUME_EPOCH_1_RECS 1 | |
141 | #define SRV_TO_CLI_RESUME_EPOCH_0_RECS 2 | |
142 | #define SRV_TO_CLI_RESUME_EPOCH_1_RECS 1 | |
143 | #define TOTAL_RESUME_HAND_RECORDS \ | |
144 | (CLI_TO_SRV_RESUME_EPOCH_0_RECS + CLI_TO_SRV_RESUME_EPOCH_1_RECS + \ | |
145 | SRV_TO_CLI_RESUME_EPOCH_0_RECS + SRV_TO_CLI_RESUME_EPOCH_1_RECS) | |
146 | ||
147 | #define TOTAL_RECORDS (TOTAL_FULL_HAND_RECORDS + TOTAL_RESUME_HAND_RECORDS) | |
148 | ||
149 | static int test_dtls_drop_records(int idx) | |
150 | { | |
151 | SSL_CTX *sctx = NULL, *cctx = NULL; | |
152 | SSL *serverssl = NULL, *clientssl = NULL; | |
153 | BIO *c_to_s_fbio, *mempackbio; | |
154 | int testresult = 0; | |
155 | int epoch = 0; | |
156 | SSL_SESSION *sess = NULL; | |
157 | int cli_to_srv_epoch0, cli_to_srv_epoch1, srv_to_cli_epoch0; | |
158 | ||
159 | if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), | |
160 | DTLS_client_method(), | |
161 | DTLS1_VERSION, DTLS_MAX_VERSION, | |
162 | &sctx, &cctx, cert, privkey))) | |
163 | return 0; | |
164 | ||
165 | if (idx >= TOTAL_FULL_HAND_RECORDS) { | |
166 | /* We're going to do a resumption handshake. Get a session first. */ | |
167 | if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, | |
168 | NULL, NULL)) | |
169 | || !TEST_true(create_ssl_connection(serverssl, clientssl, | |
170 | SSL_ERROR_NONE)) | |
171 | || !TEST_ptr(sess = SSL_get1_session(clientssl))) | |
172 | goto end; | |
173 | ||
174 | SSL_shutdown(clientssl); | |
175 | SSL_shutdown(serverssl); | |
176 | SSL_free(serverssl); | |
177 | SSL_free(clientssl); | |
178 | serverssl = clientssl = NULL; | |
179 | ||
180 | cli_to_srv_epoch0 = CLI_TO_SRV_RESUME_EPOCH_0_RECS; | |
181 | cli_to_srv_epoch1 = CLI_TO_SRV_RESUME_EPOCH_1_RECS; | |
182 | srv_to_cli_epoch0 = SRV_TO_CLI_RESUME_EPOCH_0_RECS; | |
183 | idx -= TOTAL_FULL_HAND_RECORDS; | |
184 | } else { | |
185 | cli_to_srv_epoch0 = CLI_TO_SRV_EPOCH_0_RECS; | |
186 | cli_to_srv_epoch1 = CLI_TO_SRV_EPOCH_1_RECS; | |
187 | srv_to_cli_epoch0 = SRV_TO_CLI_EPOCH_0_RECS; | |
188 | } | |
189 | ||
190 | c_to_s_fbio = BIO_new(bio_f_tls_dump_filter()); | |
191 | if (!TEST_ptr(c_to_s_fbio)) | |
192 | goto end; | |
193 | ||
194 | /* BIO is freed by create_ssl_connection on error */ | |
195 | if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, | |
196 | NULL, c_to_s_fbio))) | |
197 | goto end; | |
198 | ||
199 | if (sess != NULL) { | |
200 | if (!TEST_true(SSL_set_session(clientssl, sess))) | |
201 | goto end; | |
202 | } | |
203 | ||
204 | DTLS_set_timer_cb(clientssl, timer_cb); | |
205 | DTLS_set_timer_cb(serverssl, timer_cb); | |
206 | ||
207 | /* Work out which record to drop based on the test number */ | |
208 | if (idx >= cli_to_srv_epoch0 + cli_to_srv_epoch1) { | |
209 | mempackbio = SSL_get_wbio(serverssl); | |
210 | idx -= cli_to_srv_epoch0 + cli_to_srv_epoch1; | |
211 | if (idx >= srv_to_cli_epoch0) { | |
212 | epoch = 1; | |
213 | idx -= srv_to_cli_epoch0; | |
214 | } | |
215 | } else { | |
216 | mempackbio = SSL_get_wbio(clientssl); | |
217 | if (idx >= cli_to_srv_epoch0) { | |
218 | epoch = 1; | |
219 | idx -= cli_to_srv_epoch0; | |
220 | } | |
221 | mempackbio = BIO_next(mempackbio); | |
222 | } | |
223 | BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_EPOCH, epoch, NULL); | |
224 | BIO_ctrl(mempackbio, MEMPACKET_CTRL_SET_DROP_REC, idx, NULL); | |
225 | ||
226 | if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) | |
227 | goto end; | |
228 | ||
229 | if (sess != NULL && !TEST_true(SSL_session_reused(clientssl))) | |
230 | goto end; | |
231 | ||
232 | /* If the test did what we planned then it should have dropped a record */ | |
233 | if (!TEST_int_eq((int)BIO_ctrl(mempackbio, MEMPACKET_CTRL_GET_DROP_REC, 0, | |
234 | NULL), -1)) | |
235 | goto end; | |
236 | ||
237 | testresult = 1; | |
238 | end: | |
239 | SSL_SESSION_free(sess); | |
240 | SSL_free(serverssl); | |
241 | SSL_free(clientssl); | |
242 | SSL_CTX_free(sctx); | |
243 | SSL_CTX_free(cctx); | |
244 | ||
245 | return testresult; | |
246 | } | |
247 | ||
6c529877 MC |
248 | static const char dummy_cookie[] = "0123456"; |
249 | ||
250 | static int generate_cookie_cb(SSL *ssl, unsigned char *cookie, | |
251 | unsigned int *cookie_len) | |
252 | { | |
253 | memcpy(cookie, dummy_cookie, sizeof(dummy_cookie)); | |
254 | *cookie_len = sizeof(dummy_cookie); | |
255 | return 1; | |
256 | } | |
257 | ||
258 | static int verify_cookie_cb(SSL *ssl, const unsigned char *cookie, | |
259 | unsigned int cookie_len) | |
260 | { | |
261 | return TEST_mem_eq(cookie, cookie_len, dummy_cookie, sizeof(dummy_cookie)); | |
262 | } | |
263 | ||
264 | static int test_cookie(void) | |
265 | { | |
266 | SSL_CTX *sctx = NULL, *cctx = NULL; | |
267 | SSL *serverssl = NULL, *clientssl = NULL; | |
268 | int testresult = 0; | |
269 | ||
270 | if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), | |
271 | DTLS_client_method(), | |
272 | DTLS1_VERSION, DTLS_MAX_VERSION, | |
273 | &sctx, &cctx, cert, privkey))) | |
274 | return 0; | |
275 | ||
276 | SSL_CTX_set_options(sctx, SSL_OP_COOKIE_EXCHANGE); | |
277 | SSL_CTX_set_cookie_generate_cb(sctx, generate_cookie_cb); | |
278 | SSL_CTX_set_cookie_verify_cb(sctx, verify_cookie_cb); | |
279 | ||
280 | if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, | |
281 | NULL, NULL)) | |
282 | || !TEST_true(create_ssl_connection(serverssl, clientssl, | |
283 | SSL_ERROR_NONE))) | |
284 | goto end; | |
285 | ||
286 | testresult = 1; | |
287 | end: | |
288 | SSL_free(serverssl); | |
289 | SSL_free(clientssl); | |
290 | SSL_CTX_free(sctx); | |
291 | SSL_CTX_free(cctx); | |
292 | ||
293 | return testresult; | |
294 | } | |
295 | ||
0b3f5eab MC |
296 | static int test_dtls_duplicate_records(void) |
297 | { | |
298 | SSL_CTX *sctx = NULL, *cctx = NULL; | |
299 | SSL *serverssl = NULL, *clientssl = NULL; | |
300 | int testresult = 0; | |
301 | ||
302 | if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(), | |
303 | DTLS_client_method(), | |
304 | DTLS1_VERSION, DTLS_MAX_VERSION, | |
305 | &sctx, &cctx, cert, privkey))) | |
306 | return 0; | |
307 | ||
308 | if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, | |
309 | NULL, NULL))) | |
310 | goto end; | |
311 | ||
312 | DTLS_set_timer_cb(clientssl, timer_cb); | |
313 | DTLS_set_timer_cb(serverssl, timer_cb); | |
314 | ||
315 | BIO_ctrl(SSL_get_wbio(clientssl), MEMPACKET_CTRL_SET_DUPLICATE_REC, 1, NULL); | |
316 | BIO_ctrl(SSL_get_wbio(serverssl), MEMPACKET_CTRL_SET_DUPLICATE_REC, 1, NULL); | |
317 | ||
318 | if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) | |
319 | goto end; | |
320 | ||
321 | testresult = 1; | |
322 | end: | |
323 | SSL_free(serverssl); | |
324 | SSL_free(clientssl); | |
325 | SSL_CTX_free(sctx); | |
326 | SSL_CTX_free(cctx); | |
327 | ||
328 | return testresult; | |
329 | } | |
6c529877 | 330 | |
ad887416 | 331 | int setup_tests(void) |
6fc1748e | 332 | { |
ad887416 P |
333 | if (!TEST_ptr(cert = test_get_argument(0)) |
334 | || !TEST_ptr(privkey = test_get_argument(1))) | |
335 | return 0; | |
6fc1748e | 336 | |
ac9fc67a | 337 | ADD_ALL_TESTS(test_dtls_unprocessed, NUM_TESTS); |
61e96557 | 338 | ADD_ALL_TESTS(test_dtls_drop_records, TOTAL_RECORDS); |
6c529877 | 339 | ADD_TEST(test_cookie); |
0b3f5eab | 340 | ADD_TEST(test_dtls_duplicate_records); |
61e96557 | 341 | |
ad887416 P |
342 | return 1; |
343 | } | |
6fc1748e | 344 | |
ad887416 P |
345 | void cleanup_tests(void) |
346 | { | |
6fc1748e MC |
347 | bio_f_tls_dump_filter_free(); |
348 | bio_s_mempacket_test_free(); | |
6fc1748e | 349 | } |