diff options
author | tb <> | 2024-06-28 14:50:37 +0000 |
---|---|---|
committer | tb <> | 2024-06-28 14:50:37 +0000 |
commit | 13065e0dd0906a64b55e1d3f6ba2e08b22da7660 (patch) | |
tree | d7138c49b31f533f2fffdb2d065a8e44e4b2863c /src | |
parent | 8c0ad147db50e98dd6a31a0108ff71cd5e6ec0e5 (diff) | |
download | openbsd-13065e0dd0906a64b55e1d3f6ba2e08b22da7660.tar.gz openbsd-13065e0dd0906a64b55e1d3f6ba2e08b22da7660.tar.bz2 openbsd-13065e0dd0906a64b55e1d3f6ba2e08b22da7660.zip |
Add more regress coverage for SSL_select_next_proto()
Diffstat (limited to 'src')
-rw-r--r-- | src/regress/lib/libssl/unit/ssl_set_alpn_protos.c | 292 |
1 files changed, 291 insertions, 1 deletions
diff --git a/src/regress/lib/libssl/unit/ssl_set_alpn_protos.c b/src/regress/lib/libssl/unit/ssl_set_alpn_protos.c index 87dd4d9e5a..6f3fcfbc2a 100644 --- a/src/regress/lib/libssl/unit/ssl_set_alpn_protos.c +++ b/src/regress/lib/libssl/unit/ssl_set_alpn_protos.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_set_alpn_protos.c,v 1.2 2022/07/21 03:59:04 tb Exp $ */ | 1 | /* $OpenBSD: ssl_set_alpn_protos.c,v 1.3 2024/06/28 14:50:37 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> | 3 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> |
4 | * | 4 | * |
@@ -20,6 +20,21 @@ | |||
20 | 20 | ||
21 | #include <openssl/ssl.h> | 21 | #include <openssl/ssl.h> |
22 | 22 | ||
23 | static void | ||
24 | hexdump(const unsigned char *buf, size_t len) | ||
25 | { | ||
26 | size_t i; | ||
27 | |||
28 | if (buf == NULL) { | ||
29 | fprintf(stderr, "(null), len %zu\n", len); | ||
30 | return; | ||
31 | } | ||
32 | for (i = 1; i <= len; i++) | ||
33 | fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); | ||
34 | if (len % 8) | ||
35 | fprintf(stderr, "\n"); | ||
36 | } | ||
37 | |||
23 | struct alpn_test { | 38 | struct alpn_test { |
24 | const char *description; | 39 | const char *description; |
25 | const uint8_t protocols[24]; | 40 | const uint8_t protocols[24]; |
@@ -186,6 +201,279 @@ test_ssl_set_alpn_protos_edge_cases(void) | |||
186 | return failed; | 201 | return failed; |
187 | } | 202 | } |
188 | 203 | ||
204 | static const struct select_next_proto_test { | ||
205 | const unsigned char *server_list; | ||
206 | size_t server_list_len; | ||
207 | const unsigned char *client_list; | ||
208 | size_t client_list_len; | ||
209 | int want_ret; | ||
210 | const unsigned char *want_out; | ||
211 | unsigned char want_out_len; /* yes, unsigned char */ | ||
212 | } select_next_proto_tests[] = { | ||
213 | { | ||
214 | .server_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
215 | .server_list_len = 6, | ||
216 | .client_list = "\x01" "a", | ||
217 | .client_list_len = 2, | ||
218 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
219 | .want_out = "a", | ||
220 | .want_out_len = 1, | ||
221 | }, | ||
222 | { | ||
223 | .server_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
224 | .server_list_len = 6, | ||
225 | .client_list = "\x02" "aa" "\x01" "b" "\x01" "c", | ||
226 | .client_list_len = 7, | ||
227 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
228 | .want_out = "b", | ||
229 | .want_out_len = 1, | ||
230 | }, | ||
231 | { | ||
232 | /* Use server preference. */ | ||
233 | .server_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
234 | .server_list_len = 6, | ||
235 | .client_list = "\x01" "c" "\x01" "b" "\x01" "a", | ||
236 | .client_list_len = 6, | ||
237 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
238 | .want_out = "a", | ||
239 | .want_out_len = 1, | ||
240 | }, | ||
241 | { | ||
242 | /* Again server preference wins. */ | ||
243 | .server_list = "\x01" "a" "\x03" "bbb" "\x02" "cc", | ||
244 | .server_list_len = 9, | ||
245 | .client_list = "\x01" "z" "\x02" "cc" "\x03" "bbb", | ||
246 | .client_list_len = 9, | ||
247 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
248 | .want_out = "bbb", | ||
249 | .want_out_len = 3, | ||
250 | }, | ||
251 | { | ||
252 | /* No overlap fails with first client protocol. */ | ||
253 | .server_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
254 | .server_list_len = 6, | ||
255 | .client_list = "\x01" "z" "\x01" "y", | ||
256 | .client_list_len = 4, | ||
257 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
258 | .want_out = "z", | ||
259 | .want_out_len = 1, | ||
260 | }, | ||
261 | { | ||
262 | /* | ||
263 | * No server protocols is a misconfiguration, but should fail | ||
264 | * cleanly. | ||
265 | */ | ||
266 | .server_list = "", | ||
267 | .server_list_len = 0, | ||
268 | .client_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
269 | .client_list_len = 6, | ||
270 | .want_out = "a", | ||
271 | .want_out_len = 1, | ||
272 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
273 | }, | ||
274 | { | ||
275 | /* | ||
276 | * NULL server protocols is a programming error that fails | ||
277 | * cleanly. | ||
278 | */ | ||
279 | .server_list = NULL, | ||
280 | .server_list_len = 0, | ||
281 | .client_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
282 | .client_list_len = 6, | ||
283 | .want_out = "a", | ||
284 | .want_out_len = 1, | ||
285 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
286 | }, | ||
287 | { | ||
288 | /* | ||
289 | * Malformed server protocols is a misconfiguration, but it | ||
290 | * should fail cleanly. | ||
291 | */ | ||
292 | .server_list = "\x00", | ||
293 | .server_list_len = 1, | ||
294 | .client_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
295 | .client_list_len = 6, | ||
296 | .want_out = "a", | ||
297 | .want_out_len = 1, | ||
298 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
299 | }, | ||
300 | { | ||
301 | /* | ||
302 | * Malformed server protocols is a misconfiguration, but it | ||
303 | * should fail cleanly. | ||
304 | */ | ||
305 | .server_list = "\x01" "a" "\x03" "bb", | ||
306 | .server_list_len = 5, | ||
307 | .client_list = "\x01" "a" "\x01" "b" "\x01" "c", | ||
308 | .client_list_len = 6, | ||
309 | .want_out = "a", | ||
310 | .want_out_len = 1, | ||
311 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
312 | }, | ||
313 | { | ||
314 | /* | ||
315 | * Empty client protocols is not reachable from the ALPN | ||
316 | * callback. It fails cleanly with NULL protocol and 0 length. | ||
317 | */ | ||
318 | .server_list = "\x01" "a", | ||
319 | .server_list_len = 2, | ||
320 | .client_list = "", | ||
321 | .client_list_len = 0, | ||
322 | .want_out = NULL, | ||
323 | .want_out_len = 0, | ||
324 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
325 | }, | ||
326 | { | ||
327 | /* | ||
328 | * NULL client protocols is not reachable from the ALPN | ||
329 | * callback. It fails cleanly with NULL protocol and 0 length. | ||
330 | */ | ||
331 | .server_list = "\x01" "a", | ||
332 | .server_list_len = 2, | ||
333 | .client_list = NULL, | ||
334 | .client_list_len = 0, | ||
335 | .want_out = NULL, | ||
336 | .want_out_len = 0, | ||
337 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
338 | }, | ||
339 | { | ||
340 | /* | ||
341 | * Malformed client list fails cleanly with NULL protocol and | ||
342 | * 0 length. | ||
343 | */ | ||
344 | .server_list = "\x01" "a", | ||
345 | .server_list_len = 2, | ||
346 | .client_list = "\x01" "a" "\x02" "bb" "\x03" "cc" "\x04" "ddd", | ||
347 | .client_list_len = 12, | ||
348 | .want_out = NULL, | ||
349 | .want_out_len = 0, | ||
350 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
351 | }, | ||
352 | { | ||
353 | /* | ||
354 | * Malformed client list fails cleanly with NULL protocol and | ||
355 | * 0 length. | ||
356 | */ | ||
357 | .server_list = "\x01" "a", | ||
358 | .server_list_len = 2, | ||
359 | .client_list = "\x01" "a" "\x02" "bb" "\x00" "\x03" "ddd", | ||
360 | .client_list_len = 10, | ||
361 | .want_out = NULL, | ||
362 | .want_out_len = 0, | ||
363 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
364 | }, | ||
365 | |||
366 | /* | ||
367 | * Some non-toy examples. | ||
368 | */ | ||
369 | |||
370 | { | ||
371 | .server_list = "\x08" "http/1.1" "\x06" "spdy/1", | ||
372 | .server_list_len = 16, | ||
373 | .client_list = "\x08" "http/2.0" "\x08" "http/1.1", | ||
374 | .client_list_len = 18, | ||
375 | .want_out = "http/1.1", | ||
376 | .want_out_len = 8, | ||
377 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
378 | }, | ||
379 | { | ||
380 | .server_list = "\x08" "http/2.0" "\x06" "spdy/1", | ||
381 | .server_list_len = 16, | ||
382 | .client_list = "\x08" "http/1.0" "\x08" "http/1.1", | ||
383 | .client_list_len = 18, | ||
384 | .want_out = "http/1.0", | ||
385 | .want_out_len = 8, | ||
386 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
387 | }, | ||
388 | { | ||
389 | .server_list = "\x08" "http/1.1" "\x08" "http/1.0", | ||
390 | .server_list_len = 18, | ||
391 | .client_list = "\x08" "http/1.0" "\x08" "http/1.1", | ||
392 | .client_list_len = 18, | ||
393 | .want_out = "http/1.1", | ||
394 | .want_out_len = 8, | ||
395 | .want_ret = OPENSSL_NPN_NEGOTIATED, | ||
396 | }, | ||
397 | { | ||
398 | /* Server malformed. */ | ||
399 | .server_list = "\x08" "http/1.1" "\x07" "http/1.0", | ||
400 | .server_list_len = 18, | ||
401 | .client_list = "\x08" "http/1.0" "\x08" "http/1.1", | ||
402 | .client_list_len = 18, | ||
403 | .want_out = "http/1.0", | ||
404 | .want_out_len = 8, | ||
405 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
406 | }, | ||
407 | { | ||
408 | /* Server malformed. */ | ||
409 | .server_list = "\x07" "http/1.1" "\x08" "http/1.0", | ||
410 | .server_list_len = 18, | ||
411 | .client_list = "\x08" "http/1.0" "\x08" "http/1.1", | ||
412 | .client_list_len = 18, | ||
413 | .want_out = "http/1.0", | ||
414 | .want_out_len = 8, | ||
415 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
416 | }, | ||
417 | { | ||
418 | /* Client has trailing bytes. */ | ||
419 | .server_list = "\x08" "http/1.1" "\x08" "http/1.0", | ||
420 | .server_list_len = 18, | ||
421 | .client_list = "\x08" "http/1.0" "\x07" "http/1.1", | ||
422 | .client_list_len = 18, | ||
423 | .want_out = NULL, | ||
424 | .want_out_len = 0, | ||
425 | .want_ret = OPENSSL_NPN_NO_OVERLAP, | ||
426 | }, | ||
427 | }; | ||
428 | |||
429 | #define N_SELECT_NEXT_PROTO_TESTS \ | ||
430 | (sizeof(select_next_proto_tests) / sizeof(select_next_proto_tests[0])) | ||
431 | |||
432 | static int | ||
433 | select_next_proto_testcase(const struct select_next_proto_test *test) | ||
434 | { | ||
435 | unsigned char *out; | ||
436 | unsigned char out_len; | ||
437 | int ret; | ||
438 | int failed = 0; | ||
439 | |||
440 | ret = SSL_select_next_proto(&out, &out_len, test->server_list, | ||
441 | test->server_list_len, test->client_list, test->client_list_len); | ||
442 | |||
443 | if (ret != test->want_ret || out_len != test->want_out_len || | ||
444 | (out == NULL && test->want_out != NULL) || | ||
445 | (out != NULL && test->want_out == NULL) || | ||
446 | (out != NULL && test->want_out != NULL && | ||
447 | memcmp(out, test->want_out, out_len) != 0)) { | ||
448 | fprintf(stderr, "FAIL: ret: %u (want %u), out_len: %u (want %u)\n", | ||
449 | ret, test->want_ret, out_len, test->want_out_len); | ||
450 | fprintf(stderr, "\ngot:\n"); | ||
451 | hexdump(out, out_len); | ||
452 | fprintf(stderr, "\nwant:\n"); | ||
453 | hexdump(test->want_out, test->want_out_len); | ||
454 | fprintf(stderr, "\nserver:\n"); | ||
455 | hexdump(test->server_list, test->server_list_len); | ||
456 | fprintf(stderr, "\nclient:\n"); | ||
457 | hexdump(test->client_list, test->client_list_len); | ||
458 | fprintf(stderr, "\n"); | ||
459 | failed = 1; | ||
460 | } | ||
461 | |||
462 | return failed; | ||
463 | } | ||
464 | |||
465 | static int | ||
466 | test_ssl_select_next_proto(void) | ||
467 | { | ||
468 | size_t i; | ||
469 | int failed = 0; | ||
470 | |||
471 | for (i = 0; i < N_SELECT_NEXT_PROTO_TESTS; i++) | ||
472 | failed |= select_next_proto_testcase(&select_next_proto_tests[i]); | ||
473 | |||
474 | return failed; | ||
475 | } | ||
476 | |||
189 | int | 477 | int |
190 | main(void) | 478 | main(void) |
191 | { | 479 | { |
@@ -197,6 +485,8 @@ main(void) | |||
197 | 485 | ||
198 | failed |= test_ssl_set_alpn_protos_edge_cases(); | 486 | failed |= test_ssl_set_alpn_protos_edge_cases(); |
199 | 487 | ||
488 | failed |= test_ssl_select_next_proto(); | ||
489 | |||
200 | if (!failed) | 490 | if (!failed) |
201 | printf("PASS %s\n", __FILE__); | 491 | printf("PASS %s\n", __FILE__); |
202 | 492 | ||