1 | /*
|
---|
2 | * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License 2.0 (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 |
|
---|
10 | /*
|
---|
11 | * Unit test for Cisco DTLS1_BAD_VER session resume, as used by
|
---|
12 | * AnyConnect VPN protocol.
|
---|
13 | *
|
---|
14 | * This is designed to exercise the code paths in
|
---|
15 | * http://git.infradead.org/users/dwmw2/openconnect.git/blob/HEAD:/dtls.c
|
---|
16 | * which have frequently been affected by regressions in DTLS1_BAD_VER
|
---|
17 | * support.
|
---|
18 | *
|
---|
19 | * Note that unlike other SSL tests, we don't test against our own SSL
|
---|
20 | * server method. Firstly because we don't have one; we *only* support
|
---|
21 | * DTLS1_BAD_VER as a client. And secondly because even if that were
|
---|
22 | * fixed up it's the wrong thing to test against - because if changes
|
---|
23 | * are made in generic DTLS code which don't take DTLS1_BAD_VER into
|
---|
24 | * account, there's plenty of scope for making those changes such that
|
---|
25 | * they break *both* the client and the server in the same way.
|
---|
26 | *
|
---|
27 | * So we handle the server side manually. In a session resume there isn't
|
---|
28 | * much to be done anyway.
|
---|
29 | */
|
---|
30 | #include <string.h>
|
---|
31 |
|
---|
32 | #include <openssl/core_names.h>
|
---|
33 | #include <openssl/params.h>
|
---|
34 | #include <openssl/opensslconf.h>
|
---|
35 | #include <openssl/bio.h>
|
---|
36 | #include <openssl/crypto.h>
|
---|
37 | #include <openssl/evp.h>
|
---|
38 | #include <openssl/ssl.h>
|
---|
39 | #include <openssl/err.h>
|
---|
40 | #include <openssl/rand.h>
|
---|
41 | #include <openssl/kdf.h>
|
---|
42 | #include "internal/packet.h"
|
---|
43 | #include "internal/nelem.h"
|
---|
44 | #include "testutil.h"
|
---|
45 |
|
---|
46 | /* For DTLS1_BAD_VER packets the MAC doesn't include the handshake header */
|
---|
47 | #define MAC_OFFSET (DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH)
|
---|
48 |
|
---|
49 | static unsigned char client_random[SSL3_RANDOM_SIZE];
|
---|
50 | static unsigned char server_random[SSL3_RANDOM_SIZE];
|
---|
51 |
|
---|
52 | /* These are all generated locally, sized purely according to our own whim */
|
---|
53 | static unsigned char session_id[32];
|
---|
54 | static unsigned char master_secret[48];
|
---|
55 | static unsigned char cookie[20];
|
---|
56 |
|
---|
57 | /* We've hard-coded the cipher suite; we know it's 104 bytes */
|
---|
58 | static unsigned char key_block[104];
|
---|
59 | #define mac_key (key_block + 20)
|
---|
60 | #define dec_key (key_block + 40)
|
---|
61 | #define enc_key (key_block + 56)
|
---|
62 |
|
---|
63 | static EVP_MD_CTX *handshake_md;
|
---|
64 |
|
---|
65 | static int do_PRF(const void *seed1, int seed1_len,
|
---|
66 | const void *seed2, int seed2_len,
|
---|
67 | const void *seed3, int seed3_len,
|
---|
68 | unsigned char *out, int olen)
|
---|
69 | {
|
---|
70 | EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
|
---|
71 | size_t outlen = olen;
|
---|
72 |
|
---|
73 | /* No error handling. If it all screws up, the test will fail anyway */
|
---|
74 | EVP_PKEY_derive_init(pctx);
|
---|
75 | EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_md5_sha1());
|
---|
76 | EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, master_secret, sizeof(master_secret));
|
---|
77 | EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed1, seed1_len);
|
---|
78 | EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed2, seed2_len);
|
---|
79 | EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed3, seed3_len);
|
---|
80 | EVP_PKEY_derive(pctx, out, &outlen);
|
---|
81 | EVP_PKEY_CTX_free(pctx);
|
---|
82 | return 1;
|
---|
83 | }
|
---|
84 |
|
---|
85 | static SSL_SESSION *client_session(void)
|
---|
86 | {
|
---|
87 | static unsigned char session_asn1[] = {
|
---|
88 | 0x30, 0x5F, /* SEQUENCE, length 0x5F */
|
---|
89 | 0x02, 0x01, 0x01, /* INTEGER, SSL_SESSION_ASN1_VERSION */
|
---|
90 | 0x02, 0x02, 0x01, 0x00, /* INTEGER, DTLS1_BAD_VER */
|
---|
91 | 0x04, 0x02, 0x00, 0x2F, /* OCTET_STRING, AES128-SHA */
|
---|
92 | 0x04, 0x20, /* OCTET_STRING, session id */
|
---|
93 | #define SS_SESSID_OFS 15 /* Session ID goes here */
|
---|
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
98 | 0x04, 0x30, /* OCTET_STRING, master secret */
|
---|
99 | #define SS_SECRET_OFS 49 /* Master secret goes here */
|
---|
100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
106 | };
|
---|
107 | const unsigned char *p = session_asn1;
|
---|
108 |
|
---|
109 | /* Copy the randomly-generated fields into the above ASN1 */
|
---|
110 | memcpy(session_asn1 + SS_SESSID_OFS, session_id, sizeof(session_id));
|
---|
111 | memcpy(session_asn1 + SS_SECRET_OFS, master_secret, sizeof(master_secret));
|
---|
112 |
|
---|
113 | return d2i_SSL_SESSION(NULL, &p, sizeof(session_asn1));
|
---|
114 | }
|
---|
115 |
|
---|
116 | /* Returns 1 for initial ClientHello, 2 for ClientHello with cookie */
|
---|
117 | static int validate_client_hello(BIO *wbio)
|
---|
118 | {
|
---|
119 | PACKET pkt, pkt2;
|
---|
120 | long len;
|
---|
121 | unsigned char *data;
|
---|
122 | int cookie_found = 0;
|
---|
123 | unsigned int u = 0;
|
---|
124 |
|
---|
125 | if ((len = BIO_get_mem_data(wbio, (char **)&data)) < 0)
|
---|
126 | return 0;
|
---|
127 | if (!PACKET_buf_init(&pkt, data, len))
|
---|
128 | return 0;
|
---|
129 |
|
---|
130 | /* Check record header type */
|
---|
131 | if (!PACKET_get_1(&pkt, &u) || u != SSL3_RT_HANDSHAKE)
|
---|
132 | return 0;
|
---|
133 | /* Version */
|
---|
134 | if (!PACKET_get_net_2(&pkt, &u) || u != DTLS1_BAD_VER)
|
---|
135 | return 0;
|
---|
136 | /* Skip the rest of the record header */
|
---|
137 | if (!PACKET_forward(&pkt, DTLS1_RT_HEADER_LENGTH - 3))
|
---|
138 | return 0;
|
---|
139 |
|
---|
140 | /* Check it's a ClientHello */
|
---|
141 | if (!PACKET_get_1(&pkt, &u) || u != SSL3_MT_CLIENT_HELLO)
|
---|
142 | return 0;
|
---|
143 | /* Skip the rest of the handshake message header */
|
---|
144 | if (!PACKET_forward(&pkt, DTLS1_HM_HEADER_LENGTH - 1))
|
---|
145 | return 0;
|
---|
146 |
|
---|
147 | /* Check client version */
|
---|
148 | if (!PACKET_get_net_2(&pkt, &u) || u != DTLS1_BAD_VER)
|
---|
149 | return 0;
|
---|
150 |
|
---|
151 | /* Store random */
|
---|
152 | if (!PACKET_copy_bytes(&pkt, client_random, SSL3_RANDOM_SIZE))
|
---|
153 | return 0;
|
---|
154 |
|
---|
155 | /* Check session id length and content */
|
---|
156 | if (!PACKET_get_length_prefixed_1(&pkt, &pkt2) ||
|
---|
157 | !PACKET_equal(&pkt2, session_id, sizeof(session_id)))
|
---|
158 | return 0;
|
---|
159 |
|
---|
160 | /* Check cookie */
|
---|
161 | if (!PACKET_get_length_prefixed_1(&pkt, &pkt2))
|
---|
162 | return 0;
|
---|
163 | if (PACKET_remaining(&pkt2)) {
|
---|
164 | if (!PACKET_equal(&pkt2, cookie, sizeof(cookie)))
|
---|
165 | return 0;
|
---|
166 | cookie_found = 1;
|
---|
167 | }
|
---|
168 |
|
---|
169 | /* Skip ciphers */
|
---|
170 | if (!PACKET_get_net_2(&pkt, &u) || !PACKET_forward(&pkt, u))
|
---|
171 | return 0;
|
---|
172 |
|
---|
173 | /* Skip compression */
|
---|
174 | if (!PACKET_get_1(&pkt, &u) || !PACKET_forward(&pkt, u))
|
---|
175 | return 0;
|
---|
176 |
|
---|
177 | /* Skip extensions */
|
---|
178 | if (!PACKET_get_net_2(&pkt, &u) || !PACKET_forward(&pkt, u))
|
---|
179 | return 0;
|
---|
180 |
|
---|
181 | /* Now we are at the end */
|
---|
182 | if (PACKET_remaining(&pkt))
|
---|
183 | return 0;
|
---|
184 |
|
---|
185 | /* Update handshake MAC for second ClientHello (with cookie) */
|
---|
186 | if (cookie_found && !EVP_DigestUpdate(handshake_md, data + MAC_OFFSET,
|
---|
187 | len - MAC_OFFSET))
|
---|
188 | return 0;
|
---|
189 |
|
---|
190 | (void)BIO_reset(wbio);
|
---|
191 |
|
---|
192 | return 1 + cookie_found;
|
---|
193 | }
|
---|
194 |
|
---|
195 | static int send_hello_verify(BIO *rbio)
|
---|
196 | {
|
---|
197 | static unsigned char hello_verify[] = {
|
---|
198 | 0x16, /* Handshake */
|
---|
199 | 0x01, 0x00, /* DTLS1_BAD_VER */
|
---|
200 | 0x00, 0x00, /* Epoch 0 */
|
---|
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Seq# 0 */
|
---|
202 | 0x00, 0x23, /* Length */
|
---|
203 | 0x03, /* Hello Verify */
|
---|
204 | 0x00, 0x00, 0x17, /* Length */
|
---|
205 | 0x00, 0x00, /* Seq# 0 */
|
---|
206 | 0x00, 0x00, 0x00, /* Fragment offset */
|
---|
207 | 0x00, 0x00, 0x17, /* Fragment length */
|
---|
208 | 0x01, 0x00, /* DTLS1_BAD_VER */
|
---|
209 | 0x14, /* Cookie length */
|
---|
210 | #define HV_COOKIE_OFS 28 /* Cookie goes here */
|
---|
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
213 | 0x00, 0x00, 0x00, 0x00,
|
---|
214 | };
|
---|
215 |
|
---|
216 | memcpy(hello_verify + HV_COOKIE_OFS, cookie, sizeof(cookie));
|
---|
217 |
|
---|
218 | BIO_write(rbio, hello_verify, sizeof(hello_verify));
|
---|
219 |
|
---|
220 | return 1;
|
---|
221 | }
|
---|
222 |
|
---|
223 | static int send_server_hello(BIO *rbio)
|
---|
224 | {
|
---|
225 | static unsigned char server_hello[] = {
|
---|
226 | 0x16, /* Handshake */
|
---|
227 | 0x01, 0x00, /* DTLS1_BAD_VER */
|
---|
228 | 0x00, 0x00, /* Epoch 0 */
|
---|
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Seq# 1 */
|
---|
230 | 0x00, 0x52, /* Length */
|
---|
231 | 0x02, /* Server Hello */
|
---|
232 | 0x00, 0x00, 0x46, /* Length */
|
---|
233 | 0x00, 0x01, /* Seq# */
|
---|
234 | 0x00, 0x00, 0x00, /* Fragment offset */
|
---|
235 | 0x00, 0x00, 0x46, /* Fragment length */
|
---|
236 | 0x01, 0x00, /* DTLS1_BAD_VER */
|
---|
237 | #define SH_RANDOM_OFS 27 /* Server random goes here */
|
---|
238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
242 | 0x20, /* Session ID length */
|
---|
243 | #define SH_SESSID_OFS 60 /* Session ID goes here */
|
---|
244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
246 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
248 | 0x00, 0x2f, /* Cipher suite AES128-SHA */
|
---|
249 | 0x00, /* Compression null */
|
---|
250 | };
|
---|
251 | static unsigned char change_cipher_spec[] = {
|
---|
252 | 0x14, /* Change Cipher Spec */
|
---|
253 | 0x01, 0x00, /* DTLS1_BAD_VER */
|
---|
254 | 0x00, 0x00, /* Epoch 0 */
|
---|
255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, /* Seq# 2 */
|
---|
256 | 0x00, 0x03, /* Length */
|
---|
257 | 0x01, 0x00, 0x02, /* Message */
|
---|
258 | };
|
---|
259 |
|
---|
260 | memcpy(server_hello + SH_RANDOM_OFS, server_random, sizeof(server_random));
|
---|
261 | memcpy(server_hello + SH_SESSID_OFS, session_id, sizeof(session_id));
|
---|
262 |
|
---|
263 | if (!EVP_DigestUpdate(handshake_md, server_hello + MAC_OFFSET,
|
---|
264 | sizeof(server_hello) - MAC_OFFSET))
|
---|
265 | return 0;
|
---|
266 |
|
---|
267 | BIO_write(rbio, server_hello, sizeof(server_hello));
|
---|
268 | BIO_write(rbio, change_cipher_spec, sizeof(change_cipher_spec));
|
---|
269 |
|
---|
270 | return 1;
|
---|
271 | }
|
---|
272 |
|
---|
273 | /* Create header, HMAC, pad, encrypt and send a record */
|
---|
274 | static int send_record(BIO *rbio, unsigned char type, uint64_t seqnr,
|
---|
275 | const void *msg, size_t len)
|
---|
276 | {
|
---|
277 | /* Note that the order of the record header fields on the wire,
|
---|
278 | * and in the HMAC, is different. So we just keep them in separate
|
---|
279 | * variables and handle them individually. */
|
---|
280 | static unsigned char epoch[2] = { 0x00, 0x01 };
|
---|
281 | static unsigned char seq[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
---|
282 | static unsigned char ver[2] = { 0x01, 0x00 }; /* DTLS1_BAD_VER */
|
---|
283 | unsigned char lenbytes[2];
|
---|
284 | EVP_MAC *hmac = NULL;
|
---|
285 | EVP_MAC_CTX *ctx = NULL;
|
---|
286 | EVP_CIPHER_CTX *enc_ctx = NULL;
|
---|
287 | unsigned char iv[16];
|
---|
288 | unsigned char pad;
|
---|
289 | unsigned char *enc;
|
---|
290 | OSSL_PARAM params[2];
|
---|
291 | int ret = 0;
|
---|
292 |
|
---|
293 | seq[0] = (seqnr >> 40) & 0xff;
|
---|
294 | seq[1] = (seqnr >> 32) & 0xff;
|
---|
295 | seq[2] = (seqnr >> 24) & 0xff;
|
---|
296 | seq[3] = (seqnr >> 16) & 0xff;
|
---|
297 | seq[4] = (seqnr >> 8) & 0xff;
|
---|
298 | seq[5] = seqnr & 0xff;
|
---|
299 |
|
---|
300 | pad = 15 - ((len + SHA_DIGEST_LENGTH) % 16);
|
---|
301 | enc = OPENSSL_malloc(len + SHA_DIGEST_LENGTH + 1 + pad);
|
---|
302 | if (enc == NULL)
|
---|
303 | return 0;
|
---|
304 |
|
---|
305 | /* Copy record to encryption buffer */
|
---|
306 | memcpy(enc, msg, len);
|
---|
307 |
|
---|
308 | /* Append HMAC to data */
|
---|
309 | if (!TEST_ptr(hmac = EVP_MAC_fetch(NULL, "HMAC", NULL))
|
---|
310 | || !TEST_ptr(ctx = EVP_MAC_CTX_new(hmac)))
|
---|
311 | goto end;
|
---|
312 | params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
|
---|
313 | "SHA1", 0);
|
---|
314 | params[1] = OSSL_PARAM_construct_end();
|
---|
315 | lenbytes[0] = (unsigned char)(len >> 8);
|
---|
316 | lenbytes[1] = (unsigned char)(len);
|
---|
317 | if (!EVP_MAC_init(ctx, mac_key, 20, params)
|
---|
318 | || !EVP_MAC_update(ctx, epoch, 2)
|
---|
319 | || !EVP_MAC_update(ctx, seq, 6)
|
---|
320 | || !EVP_MAC_update(ctx, &type, 1)
|
---|
321 | || !EVP_MAC_update(ctx, ver, 2) /* Version */
|
---|
322 | || !EVP_MAC_update(ctx, lenbytes, 2) /* Length */
|
---|
323 | || !EVP_MAC_update(ctx, enc, len) /* Finally the data itself */
|
---|
324 | || !EVP_MAC_final(ctx, enc + len, NULL, SHA_DIGEST_LENGTH))
|
---|
325 | goto end;
|
---|
326 |
|
---|
327 | /* Append padding bytes */
|
---|
328 | len += SHA_DIGEST_LENGTH;
|
---|
329 | do {
|
---|
330 | enc[len++] = pad;
|
---|
331 | } while (len % 16);
|
---|
332 |
|
---|
333 | /* Generate IV, and encrypt */
|
---|
334 | if (!TEST_int_gt(RAND_bytes(iv, sizeof(iv)), 0)
|
---|
335 | || !TEST_ptr(enc_ctx = EVP_CIPHER_CTX_new())
|
---|
336 | || !TEST_true(EVP_CipherInit_ex(enc_ctx, EVP_aes_128_cbc(), NULL,
|
---|
337 | enc_key, iv, 1))
|
---|
338 | || !TEST_int_ge(EVP_Cipher(enc_ctx, enc, enc, len), 0))
|
---|
339 | goto end;
|
---|
340 |
|
---|
341 | /* Finally write header (from fragmented variables), IV and encrypted record */
|
---|
342 | BIO_write(rbio, &type, 1);
|
---|
343 | BIO_write(rbio, ver, 2);
|
---|
344 | BIO_write(rbio, epoch, 2);
|
---|
345 | BIO_write(rbio, seq, 6);
|
---|
346 | lenbytes[0] = (unsigned char)((len + sizeof(iv)) >> 8);
|
---|
347 | lenbytes[1] = (unsigned char)(len + sizeof(iv));
|
---|
348 | BIO_write(rbio, lenbytes, 2);
|
---|
349 |
|
---|
350 | BIO_write(rbio, iv, sizeof(iv));
|
---|
351 | BIO_write(rbio, enc, len);
|
---|
352 | ret = 1;
|
---|
353 | end:
|
---|
354 | EVP_MAC_free(hmac);
|
---|
355 | EVP_MAC_CTX_free(ctx);
|
---|
356 | EVP_CIPHER_CTX_free(enc_ctx);
|
---|
357 | OPENSSL_free(enc);
|
---|
358 | return ret;
|
---|
359 | }
|
---|
360 |
|
---|
361 | static int send_finished(SSL *s, BIO *rbio)
|
---|
362 | {
|
---|
363 | static unsigned char finished_msg[DTLS1_HM_HEADER_LENGTH +
|
---|
364 | TLS1_FINISH_MAC_LENGTH] = {
|
---|
365 | 0x14, /* Finished */
|
---|
366 | 0x00, 0x00, 0x0c, /* Length */
|
---|
367 | 0x00, 0x03, /* Seq# 3 */
|
---|
368 | 0x00, 0x00, 0x00, /* Fragment offset */
|
---|
369 | 0x00, 0x00, 0x0c, /* Fragment length */
|
---|
370 | /* Finished MAC (12 bytes) */
|
---|
371 | };
|
---|
372 | unsigned char handshake_hash[EVP_MAX_MD_SIZE];
|
---|
373 |
|
---|
374 | /* Derive key material */
|
---|
375 | do_PRF(TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
|
---|
376 | server_random, SSL3_RANDOM_SIZE,
|
---|
377 | client_random, SSL3_RANDOM_SIZE,
|
---|
378 | key_block, sizeof(key_block));
|
---|
379 |
|
---|
380 | /* Generate Finished MAC */
|
---|
381 | if (!EVP_DigestFinal_ex(handshake_md, handshake_hash, NULL))
|
---|
382 | return 0;
|
---|
383 |
|
---|
384 | do_PRF(TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
|
---|
385 | handshake_hash, EVP_MD_CTX_get_size(handshake_md),
|
---|
386 | NULL, 0,
|
---|
387 | finished_msg + DTLS1_HM_HEADER_LENGTH, TLS1_FINISH_MAC_LENGTH);
|
---|
388 |
|
---|
389 | return send_record(rbio, SSL3_RT_HANDSHAKE, 0,
|
---|
390 | finished_msg, sizeof(finished_msg));
|
---|
391 | }
|
---|
392 |
|
---|
393 | static int validate_ccs(BIO *wbio)
|
---|
394 | {
|
---|
395 | PACKET pkt;
|
---|
396 | long len;
|
---|
397 | unsigned char *data;
|
---|
398 | unsigned int u;
|
---|
399 |
|
---|
400 | len = BIO_get_mem_data(wbio, (char **)&data);
|
---|
401 | if (len < 0)
|
---|
402 | return 0;
|
---|
403 |
|
---|
404 | if (!PACKET_buf_init(&pkt, data, len))
|
---|
405 | return 0;
|
---|
406 |
|
---|
407 | /* Check record header type */
|
---|
408 | if (!PACKET_get_1(&pkt, &u) || u != SSL3_RT_CHANGE_CIPHER_SPEC)
|
---|
409 | return 0;
|
---|
410 | /* Version */
|
---|
411 | if (!PACKET_get_net_2(&pkt, &u) || u != DTLS1_BAD_VER)
|
---|
412 | return 0;
|
---|
413 | /* Skip the rest of the record header */
|
---|
414 | if (!PACKET_forward(&pkt, DTLS1_RT_HEADER_LENGTH - 3))
|
---|
415 | return 0;
|
---|
416 |
|
---|
417 | /* Check ChangeCipherSpec message */
|
---|
418 | if (!PACKET_get_1(&pkt, &u) || u != SSL3_MT_CCS)
|
---|
419 | return 0;
|
---|
420 | /* A DTLS1_BAD_VER ChangeCipherSpec also contains the
|
---|
421 | * handshake sequence number (which is 2 here) */
|
---|
422 | if (!PACKET_get_net_2(&pkt, &u) || u != 0x0002)
|
---|
423 | return 0;
|
---|
424 |
|
---|
425 | /* Now check the Finished packet */
|
---|
426 | if (!PACKET_get_1(&pkt, &u) || u != SSL3_RT_HANDSHAKE)
|
---|
427 | return 0;
|
---|
428 | if (!PACKET_get_net_2(&pkt, &u) || u != DTLS1_BAD_VER)
|
---|
429 | return 0;
|
---|
430 |
|
---|
431 | /* Check epoch is now 1 */
|
---|
432 | if (!PACKET_get_net_2(&pkt, &u) || u != 0x0001)
|
---|
433 | return 0;
|
---|
434 |
|
---|
435 | /* That'll do for now. If OpenSSL accepted *our* Finished packet
|
---|
436 | * then it's evidently remembered that DTLS1_BAD_VER doesn't
|
---|
437 | * include the handshake header in the MAC. There's not a lot of
|
---|
438 | * point in implementing decryption here, just to check that it
|
---|
439 | * continues to get it right for one more packet. */
|
---|
440 |
|
---|
441 | return 1;
|
---|
442 | }
|
---|
443 |
|
---|
444 | #define NODROP(x) { x##UL, 0 }
|
---|
445 | #define DROP(x) { x##UL, 1 }
|
---|
446 |
|
---|
447 | static struct {
|
---|
448 | uint64_t seq;
|
---|
449 | int drop;
|
---|
450 | } tests[] = {
|
---|
451 | NODROP(1), NODROP(3), NODROP(2),
|
---|
452 | NODROP(0x1234), NODROP(0x1230), NODROP(0x1235),
|
---|
453 | NODROP(0xffff), NODROP(0x10001), NODROP(0xfffe), NODROP(0x10000),
|
---|
454 | DROP(0x10001), DROP(0xff), NODROP(0x100000), NODROP(0x800000), NODROP(0x7fffe1),
|
---|
455 | NODROP(0xffffff), NODROP(0x1000000), NODROP(0xfffffe), DROP(0xffffff), NODROP(0x1000010),
|
---|
456 | NODROP(0xfffffd), NODROP(0x1000011), DROP(0x12), NODROP(0x1000012),
|
---|
457 | NODROP(0x1ffffff), NODROP(0x2000000), DROP(0x1ff00fe), NODROP(0x2000001),
|
---|
458 | NODROP(0x20fffff), NODROP(0x2105500), DROP(0x20ffffe), NODROP(0x21054ff),
|
---|
459 | NODROP(0x211ffff), DROP(0x2110000), NODROP(0x2120000)
|
---|
460 | /* The last test should be NODROP, because a DROP wouldn't get tested. */
|
---|
461 | };
|
---|
462 |
|
---|
463 | static int test_bad_dtls(void)
|
---|
464 | {
|
---|
465 | SSL_SESSION *sess = NULL;
|
---|
466 | SSL_CTX *ctx = NULL;
|
---|
467 | SSL *con = NULL;
|
---|
468 | BIO *rbio = NULL;
|
---|
469 | BIO *wbio = NULL;
|
---|
470 | time_t now = 0;
|
---|
471 | int testresult = 0;
|
---|
472 | int ret;
|
---|
473 | int i;
|
---|
474 |
|
---|
475 | RAND_bytes(session_id, sizeof(session_id));
|
---|
476 | RAND_bytes(master_secret, sizeof(master_secret));
|
---|
477 | RAND_bytes(cookie, sizeof(cookie));
|
---|
478 | RAND_bytes(server_random + 4, sizeof(server_random) - 4);
|
---|
479 |
|
---|
480 | now = time(NULL);
|
---|
481 | memcpy(server_random, &now, sizeof(now));
|
---|
482 |
|
---|
483 | sess = client_session();
|
---|
484 | if (!TEST_ptr(sess))
|
---|
485 | goto end;
|
---|
486 |
|
---|
487 | handshake_md = EVP_MD_CTX_new();
|
---|
488 | if (!TEST_ptr(handshake_md)
|
---|
489 | || !TEST_true(EVP_DigestInit_ex(handshake_md, EVP_md5_sha1(),
|
---|
490 | NULL)))
|
---|
491 | goto end;
|
---|
492 |
|
---|
493 | ctx = SSL_CTX_new(DTLS_client_method());
|
---|
494 | if (!TEST_ptr(ctx)
|
---|
495 | || !TEST_true(SSL_CTX_set_min_proto_version(ctx, DTLS1_BAD_VER))
|
---|
496 | || !TEST_true(SSL_CTX_set_max_proto_version(ctx, DTLS1_BAD_VER))
|
---|
497 | || !TEST_true(SSL_CTX_set_options(ctx,
|
---|
498 | SSL_OP_LEGACY_SERVER_CONNECT))
|
---|
499 | || !TEST_true(SSL_CTX_set_cipher_list(ctx, "AES128-SHA")))
|
---|
500 | goto end;
|
---|
501 |
|
---|
502 | SSL_CTX_set_security_level(ctx, 0);
|
---|
503 | con = SSL_new(ctx);
|
---|
504 | if (!TEST_ptr(con)
|
---|
505 | || !TEST_true(SSL_set_session(con, sess)))
|
---|
506 | goto end;
|
---|
507 | SSL_SESSION_free(sess);
|
---|
508 |
|
---|
509 | rbio = BIO_new(BIO_s_mem());
|
---|
510 | wbio = BIO_new(BIO_s_mem());
|
---|
511 |
|
---|
512 | if (!TEST_ptr(rbio)
|
---|
513 | || !TEST_ptr(wbio))
|
---|
514 | goto end;
|
---|
515 |
|
---|
516 | SSL_set_bio(con, rbio, wbio);
|
---|
517 |
|
---|
518 | if (!TEST_true(BIO_up_ref(rbio))) {
|
---|
519 | /*
|
---|
520 | * We can't up-ref but we assigned ownership to con, so we shouldn't
|
---|
521 | * free in the "end" block
|
---|
522 | */
|
---|
523 | rbio = wbio = NULL;
|
---|
524 | goto end;
|
---|
525 | }
|
---|
526 |
|
---|
527 | if (!TEST_true(BIO_up_ref(wbio))) {
|
---|
528 | wbio = NULL;
|
---|
529 | goto end;
|
---|
530 | }
|
---|
531 |
|
---|
532 | SSL_set_connect_state(con);
|
---|
533 |
|
---|
534 | /* Send initial ClientHello */
|
---|
535 | ret = SSL_do_handshake(con);
|
---|
536 | if (!TEST_int_le(ret, 0)
|
---|
537 | || !TEST_int_eq(SSL_get_error(con, ret), SSL_ERROR_WANT_READ)
|
---|
538 | || !TEST_int_eq(validate_client_hello(wbio), 1)
|
---|
539 | || !TEST_true(send_hello_verify(rbio)))
|
---|
540 | goto end;
|
---|
541 |
|
---|
542 | ret = SSL_do_handshake(con);
|
---|
543 | if (!TEST_int_le(ret, 0)
|
---|
544 | || !TEST_int_eq(SSL_get_error(con, ret), SSL_ERROR_WANT_READ)
|
---|
545 | || !TEST_int_eq(validate_client_hello(wbio), 2)
|
---|
546 | || !TEST_true(send_server_hello(rbio)))
|
---|
547 | goto end;
|
---|
548 |
|
---|
549 | ret = SSL_do_handshake(con);
|
---|
550 | if (!TEST_int_le(ret, 0)
|
---|
551 | || !TEST_int_eq(SSL_get_error(con, ret), SSL_ERROR_WANT_READ)
|
---|
552 | || !TEST_true(send_finished(con, rbio)))
|
---|
553 | goto end;
|
---|
554 |
|
---|
555 | ret = SSL_do_handshake(con);
|
---|
556 | if (!TEST_int_gt(ret, 0)
|
---|
557 | || !TEST_true(validate_ccs(wbio)))
|
---|
558 | goto end;
|
---|
559 |
|
---|
560 | /* While we're here and crafting packets by hand, we might as well do a
|
---|
561 | bit of a stress test on the DTLS record replay handling. Not Cisco-DTLS
|
---|
562 | specific but useful anyway for the general case. It's been broken
|
---|
563 | before, and in fact was broken even for a basic 0, 2, 1 test case
|
---|
564 | when this test was first added.... */
|
---|
565 | for (i = 0; i < (int)OSSL_NELEM(tests); i++) {
|
---|
566 | uint64_t recv_buf[2];
|
---|
567 |
|
---|
568 | if (!TEST_true(send_record(rbio, SSL3_RT_APPLICATION_DATA, tests[i].seq,
|
---|
569 | &tests[i].seq, sizeof(uint64_t)))) {
|
---|
570 | TEST_error("Failed to send data seq #0x%x%08x (%d)\n",
|
---|
571 | (unsigned int)(tests[i].seq >> 32), (unsigned int)tests[i].seq, i);
|
---|
572 | goto end;
|
---|
573 | }
|
---|
574 |
|
---|
575 | if (tests[i].drop)
|
---|
576 | continue;
|
---|
577 |
|
---|
578 | ret = SSL_read(con, recv_buf, 2 * sizeof(uint64_t));
|
---|
579 | if (!TEST_int_eq(ret, (int)sizeof(uint64_t))) {
|
---|
580 | TEST_error("SSL_read failed or wrong size on seq#0x%x%08x (%d)\n",
|
---|
581 | (unsigned int)(tests[i].seq >> 32), (unsigned int)tests[i].seq, i);
|
---|
582 | goto end;
|
---|
583 | }
|
---|
584 | if (!TEST_true(recv_buf[0] == tests[i].seq))
|
---|
585 | goto end;
|
---|
586 | }
|
---|
587 |
|
---|
588 | /* The last test cannot be DROP() */
|
---|
589 | if (!TEST_false(tests[i-1].drop))
|
---|
590 | goto end;
|
---|
591 |
|
---|
592 | testresult = 1;
|
---|
593 |
|
---|
594 | end:
|
---|
595 | BIO_free(rbio);
|
---|
596 | BIO_free(wbio);
|
---|
597 | SSL_free(con);
|
---|
598 | SSL_CTX_free(ctx);
|
---|
599 | EVP_MD_CTX_free(handshake_md);
|
---|
600 |
|
---|
601 | return testresult;
|
---|
602 | }
|
---|
603 |
|
---|
604 | int setup_tests(void)
|
---|
605 | {
|
---|
606 | ADD_TEST(test_bad_dtls);
|
---|
607 | return 1;
|
---|
608 | }
|
---|