diff options
author | doug <> | 2017-08-12 21:17:03 +0000 |
---|---|---|
committer | doug <> | 2017-08-12 21:17:03 +0000 |
commit | 7b1e2bed428777bb9ee601d6775aa91efdc80340 (patch) | |
tree | a6945bbfcf083598e38feabf2ece8ed3cbfaed2b /src | |
parent | 8bf5f970305d128e9bff3306420305d1a510a83f (diff) | |
download | openbsd-7b1e2bed428777bb9ee601d6775aa91efdc80340.tar.gz openbsd-7b1e2bed428777bb9ee601d6775aa91efdc80340.tar.bz2 openbsd-7b1e2bed428777bb9ee601d6775aa91efdc80340.zip |
Rewrite session ticket TLS extension handling using CBB/CBS and the new
extension framework.
ok jsing@ beck@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libssl/ssl_tlsext.c | 136 | ||||
-rw-r--r-- | src/lib/libssl/ssl_tlsext.h | 8 | ||||
-rw-r--r-- | src/lib/libssl/t1_lib.c | 66 | ||||
-rw-r--r-- | src/regress/lib/libssl/tlsext/tlsexttest.c | 303 |
4 files changed, 447 insertions, 66 deletions
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c index c050224c70..1813d46f41 100644 --- a/src/lib/libssl/ssl_tlsext.c +++ b/src/lib/libssl/ssl_tlsext.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_tlsext.c,v 1.6 2017/08/11 20:14:13 doug Exp $ */ | 1 | /* $OpenBSD: ssl_tlsext.c,v 1.7 2017/08/12 21:17:03 doug Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
@@ -492,6 +492,131 @@ tlsext_sni_serverhello_parse(SSL *s, CBS *cbs, int *alert) | |||
492 | return 1; | 492 | return 1; |
493 | } | 493 | } |
494 | 494 | ||
495 | /* | ||
496 | * SessionTicket extension - RFC 5077 section 3.2 | ||
497 | */ | ||
498 | int | ||
499 | tlsext_sessionticket_clienthello_needs(SSL *s) | ||
500 | { | ||
501 | /* | ||
502 | * Send session ticket extension when enabled and not overridden. | ||
503 | * | ||
504 | * When renegotiating, send an empty session ticket to indicate support. | ||
505 | */ | ||
506 | if ((SSL_get_options(s) & SSL_OP_NO_TICKET) != 0) | ||
507 | return 0; | ||
508 | |||
509 | if (s->internal->new_session) | ||
510 | return 1; | ||
511 | |||
512 | if (s->internal->tlsext_session_ticket != NULL && | ||
513 | s->internal->tlsext_session_ticket->data == NULL) | ||
514 | return 0; | ||
515 | |||
516 | return 1; | ||
517 | } | ||
518 | |||
519 | int | ||
520 | tlsext_sessionticket_clienthello_build(SSL *s, CBB *cbb) | ||
521 | { | ||
522 | /* | ||
523 | * Signal that we support session tickets by sending an empty | ||
524 | * extension when renegotiating or no session found. | ||
525 | */ | ||
526 | if (s->internal->new_session || s->session == NULL) | ||
527 | return 1; | ||
528 | |||
529 | if (s->session->tlsext_tick != NULL) { | ||
530 | /* Attempt to resume with an existing session ticket */ | ||
531 | if (!CBB_add_bytes(cbb, s->session->tlsext_tick, | ||
532 | s->session->tlsext_ticklen)) | ||
533 | return 0; | ||
534 | |||
535 | } else if (s->internal->tlsext_session_ticket != NULL) { | ||
536 | /* | ||
537 | * Attempt to resume with a custom provided session ticket set | ||
538 | * by SSL_set_session_ticket_ext(). | ||
539 | */ | ||
540 | if (s->internal->tlsext_session_ticket->length > 0) { | ||
541 | size_t ticklen = s->internal->tlsext_session_ticket->length; | ||
542 | |||
543 | if ((s->session->tlsext_tick = malloc(ticklen)) == NULL) | ||
544 | return 0; | ||
545 | memcpy(s->session->tlsext_tick, | ||
546 | s->internal->tlsext_session_ticket->data, | ||
547 | ticklen); | ||
548 | s->session->tlsext_ticklen = ticklen; | ||
549 | |||
550 | if (!CBB_add_bytes(cbb, s->session->tlsext_tick, | ||
551 | s->session->tlsext_ticklen)) | ||
552 | return 0; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if (!CBB_flush(cbb)) | ||
557 | return 0; | ||
558 | |||
559 | return 1; | ||
560 | } | ||
561 | |||
562 | int | ||
563 | tlsext_sessionticket_clienthello_parse(SSL *s, CBS *cbs, int *alert) | ||
564 | { | ||
565 | if (s->internal->tls_session_ticket_ext_cb) { | ||
566 | if (!s->internal->tls_session_ticket_ext_cb(s, CBS_data(cbs), | ||
567 | (int)CBS_len(cbs), | ||
568 | s->internal->tls_session_ticket_ext_cb_arg)) { | ||
569 | *alert = TLS1_AD_INTERNAL_ERROR; | ||
570 | return 0; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | /* We need to signal that this was processed fully */ | ||
575 | if (!CBS_skip(cbs, CBS_len(cbs))) { | ||
576 | *alert = TLS1_AD_INTERNAL_ERROR; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | return 1; | ||
581 | } | ||
582 | |||
583 | int | ||
584 | tlsext_sessionticket_serverhello_needs(SSL *s) | ||
585 | { | ||
586 | return (s->internal->tlsext_ticket_expected && | ||
587 | !(SSL_get_options(s) & SSL_OP_NO_TICKET)); | ||
588 | } | ||
589 | |||
590 | int | ||
591 | tlsext_sessionticket_serverhello_build(SSL *s, CBB *cbb) | ||
592 | { | ||
593 | /* Empty ticket */ | ||
594 | |||
595 | return 1; | ||
596 | } | ||
597 | |||
598 | int | ||
599 | tlsext_sessionticket_serverhello_parse(SSL *s, CBS *cbs, int *alert) | ||
600 | { | ||
601 | if (s->internal->tls_session_ticket_ext_cb) { | ||
602 | if (!s->internal->tls_session_ticket_ext_cb(s, CBS_data(cbs), | ||
603 | (int)CBS_len(cbs), | ||
604 | s->internal->tls_session_ticket_ext_cb_arg)) { | ||
605 | *alert = TLS1_AD_INTERNAL_ERROR; | ||
606 | return 0; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | if ((SSL_get_options(s) & SSL_OP_NO_TICKET) != 0 || CBS_len(cbs) > 0) { | ||
611 | *alert = TLS1_AD_UNSUPPORTED_EXTENSION; | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | s->internal->tlsext_ticket_expected = 1; | ||
616 | |||
617 | return 1; | ||
618 | } | ||
619 | |||
495 | struct tls_extension { | 620 | struct tls_extension { |
496 | uint16_t type; | 621 | uint16_t type; |
497 | int (*clienthello_needs)(SSL *s); | 622 | int (*clienthello_needs)(SSL *s); |
@@ -539,6 +664,15 @@ static struct tls_extension tls_extensions[] = { | |||
539 | .serverhello_build = tlsext_ec_serverhello_build, | 664 | .serverhello_build = tlsext_ec_serverhello_build, |
540 | .serverhello_parse = tlsext_ec_serverhello_parse, | 665 | .serverhello_parse = tlsext_ec_serverhello_parse, |
541 | }, | 666 | }, |
667 | { | ||
668 | .type = TLSEXT_TYPE_session_ticket, | ||
669 | .clienthello_needs = tlsext_sessionticket_clienthello_needs, | ||
670 | .clienthello_build = tlsext_sessionticket_clienthello_build, | ||
671 | .clienthello_parse = tlsext_sessionticket_clienthello_parse, | ||
672 | .serverhello_needs = tlsext_sessionticket_serverhello_needs, | ||
673 | .serverhello_build = tlsext_sessionticket_serverhello_build, | ||
674 | .serverhello_parse = tlsext_sessionticket_serverhello_parse, | ||
675 | }, | ||
542 | }; | 676 | }; |
543 | 677 | ||
544 | #define N_TLS_EXTENSIONS (sizeof(tls_extensions) / sizeof(*tls_extensions)) | 678 | #define N_TLS_EXTENSIONS (sizeof(tls_extensions) / sizeof(*tls_extensions)) |
diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h index 38f8ffaa65..1e701e941a 100644 --- a/src/lib/libssl/ssl_tlsext.h +++ b/src/lib/libssl/ssl_tlsext.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_tlsext.h,v 1.5 2017/08/11 20:14:13 doug Exp $ */ | 1 | /* $OpenBSD: ssl_tlsext.h,v 1.6 2017/08/12 21:17:03 doug Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
@@ -44,6 +44,12 @@ int tlsext_ecpf_serverhello_needs(SSL *s); | |||
44 | int tlsext_ecpf_serverhello_build(SSL *s, CBB *cbb); | 44 | int tlsext_ecpf_serverhello_build(SSL *s, CBB *cbb); |
45 | int tlsext_ecpf_serverhello_parse(SSL *s, CBS *cbs, int *alert); | 45 | int tlsext_ecpf_serverhello_parse(SSL *s, CBS *cbs, int *alert); |
46 | 46 | ||
47 | int tlsext_sessionticket_clienthello_needs(SSL *s); | ||
48 | int tlsext_sessionticket_clienthello_build(SSL *s, CBB *cbb); | ||
49 | int tlsext_sessionticket_clienthello_parse(SSL *s, CBS *cbs, int *alert); | ||
50 | int tlsext_sessionticket_serverhello_needs(SSL *s); | ||
51 | int tlsext_sessionticket_serverhello_build(SSL *s, CBB *cbb); | ||
52 | int tlsext_sessionticket_serverhello_parse(SSL *s, CBS *cbs, int *alert); | ||
47 | 53 | ||
48 | int tlsext_clienthello_build(SSL *s, CBB *cbb); | 54 | int tlsext_clienthello_build(SSL *s, CBB *cbb); |
49 | int tlsext_clienthello_parse_one(SSL *s, CBS *cbs, uint16_t tlsext_type, | 55 | int tlsext_clienthello_parse_one(SSL *s, CBS *cbs, uint16_t tlsext_type, |
diff --git a/src/lib/libssl/t1_lib.c b/src/lib/libssl/t1_lib.c index 911e8d3f4e..63d401c337 100644 --- a/src/lib/libssl/t1_lib.c +++ b/src/lib/libssl/t1_lib.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: t1_lib.c,v 1.128 2017/08/12 21:03:08 jsing Exp $ */ | 1 | /* $OpenBSD: t1_lib.c,v 1.129 2017/08/12 21:17:03 doug Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -690,39 +690,6 @@ ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) | |||
690 | return NULL; | 690 | return NULL; |
691 | ret += len; | 691 | ret += len; |
692 | 692 | ||
693 | if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { | ||
694 | int ticklen; | ||
695 | if (!s->internal->new_session && s->session && s->session->tlsext_tick) | ||
696 | ticklen = s->session->tlsext_ticklen; | ||
697 | else if (s->session && s->internal->tlsext_session_ticket && | ||
698 | s->internal->tlsext_session_ticket->data) { | ||
699 | ticklen = s->internal->tlsext_session_ticket->length; | ||
700 | s->session->tlsext_tick = malloc(ticklen); | ||
701 | if (!s->session->tlsext_tick) | ||
702 | return NULL; | ||
703 | memcpy(s->session->tlsext_tick, | ||
704 | s->internal->tlsext_session_ticket->data, ticklen); | ||
705 | s->session->tlsext_ticklen = ticklen; | ||
706 | } else | ||
707 | ticklen = 0; | ||
708 | if (ticklen == 0 && s->internal->tlsext_session_ticket && | ||
709 | s->internal->tlsext_session_ticket->data == NULL) | ||
710 | goto skip_ext; | ||
711 | /* Check for enough room 2 for extension type, 2 for len | ||
712 | * rest for ticket | ||
713 | */ | ||
714 | if ((size_t)(limit - ret) < 4 + ticklen) | ||
715 | return NULL; | ||
716 | s2n(TLSEXT_TYPE_session_ticket, ret); | ||
717 | |||
718 | s2n(ticklen, ret); | ||
719 | if (ticklen) { | ||
720 | memcpy(ret, s->session->tlsext_tick, ticklen); | ||
721 | ret += ticklen; | ||
722 | } | ||
723 | } | ||
724 | skip_ext: | ||
725 | |||
726 | if (TLS1_get_client_version(s) >= TLS1_2_VERSION) { | 693 | if (TLS1_get_client_version(s) >= TLS1_2_VERSION) { |
727 | if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6) | 694 | if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6) |
728 | return NULL; | 695 | return NULL; |
@@ -884,15 +851,6 @@ ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) | |||
884 | * extension. | 851 | * extension. |
885 | */ | 852 | */ |
886 | 853 | ||
887 | if (s->internal->tlsext_ticket_expected && | ||
888 | !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { | ||
889 | if ((size_t)(limit - ret) < 4) | ||
890 | return NULL; | ||
891 | |||
892 | s2n(TLSEXT_TYPE_session_ticket, ret); | ||
893 | s2n(0, ret); | ||
894 | } | ||
895 | |||
896 | if (s->internal->tlsext_status_expected) { | 854 | if (s->internal->tlsext_status_expected) { |
897 | if ((size_t)(limit - ret) < 4) | 855 | if ((size_t)(limit - ret) < 4) |
898 | return NULL; | 856 | return NULL; |
@@ -1068,13 +1026,7 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, | |||
1068 | if (!tlsext_clienthello_parse_one(s, &cbs, type, al)) | 1026 | if (!tlsext_clienthello_parse_one(s, &cbs, type, al)) |
1069 | return 0; | 1027 | return 0; |
1070 | 1028 | ||
1071 | if (type == TLSEXT_TYPE_session_ticket) { | 1029 | if (type == TLSEXT_TYPE_signature_algorithms) { |
1072 | if (s->internal->tls_session_ticket_ext_cb && | ||
1073 | !s->internal->tls_session_ticket_ext_cb(s, data, size, s->internal->tls_session_ticket_ext_cb_arg)) { | ||
1074 | *al = TLS1_AD_INTERNAL_ERROR; | ||
1075 | return 0; | ||
1076 | } | ||
1077 | } else if (type == TLSEXT_TYPE_signature_algorithms) { | ||
1078 | int dsize; | 1030 | int dsize; |
1079 | if (sigalg_seen || size < 2) { | 1031 | if (sigalg_seen || size < 2) { |
1080 | *al = SSL_AD_DECODE_ERROR; | 1032 | *al = SSL_AD_DECODE_ERROR; |
@@ -1277,19 +1229,7 @@ ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, size_t n, int *al) | |||
1277 | if (!tlsext_serverhello_parse_one(s, &cbs, type, al)) | 1229 | if (!tlsext_serverhello_parse_one(s, &cbs, type, al)) |
1278 | return 0; | 1230 | return 0; |
1279 | 1231 | ||
1280 | if (type == TLSEXT_TYPE_session_ticket) { | 1232 | if (type == TLSEXT_TYPE_status_request && |
1281 | if (s->internal->tls_session_ticket_ext_cb && | ||
1282 | !s->internal->tls_session_ticket_ext_cb(s, data, size, s->internal->tls_session_ticket_ext_cb_arg)) { | ||
1283 | *al = TLS1_AD_INTERNAL_ERROR; | ||
1284 | return 0; | ||
1285 | } | ||
1286 | if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || (size > 0)) { | ||
1287 | *al = TLS1_AD_UNSUPPORTED_EXTENSION; | ||
1288 | return 0; | ||
1289 | } | ||
1290 | s->internal->tlsext_ticket_expected = 1; | ||
1291 | } | ||
1292 | else if (type == TLSEXT_TYPE_status_request && | ||
1293 | s->version != DTLS1_VERSION) { | 1233 | s->version != DTLS1_VERSION) { |
1294 | /* MUST be empty and only sent if we've requested | 1234 | /* MUST be empty and only sent if we've requested |
1295 | * a status request message. | 1235 | * a status request message. |
diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c index 880142202e..1267f50a49 100644 --- a/src/regress/lib/libssl/tlsext/tlsexttest.c +++ b/src/regress/lib/libssl/tlsext/tlsexttest.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tlsexttest.c,v 1.9 2017/08/12 19:09:37 beck Exp $ */ | 1 | /* $OpenBSD: tlsexttest.c,v 1.10 2017/08/12 21:17:03 doug Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2017 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2017 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
@@ -1298,6 +1298,304 @@ test_tlsext_sni_serverhello(void) | |||
1298 | return (failure); | 1298 | return (failure); |
1299 | } | 1299 | } |
1300 | 1300 | ||
1301 | /* | ||
1302 | * Session ticket - RFC 5077 since no known implementations use 4507. | ||
1303 | * | ||
1304 | * Session tickets can be length 0 (special case) to 2^16-1. | ||
1305 | * | ||
1306 | * The state is encrypted by the server so it is opaque to the client. | ||
1307 | */ | ||
1308 | static uint8_t tlsext_sessionticket_hello_min[1]; | ||
1309 | static uint8_t tlsext_sessionticket_hello_max[65535]; | ||
1310 | |||
1311 | static int | ||
1312 | test_tlsext_sessionticket_clienthello(void) | ||
1313 | { | ||
1314 | unsigned char *data = NULL; | ||
1315 | SSL_CTX *ssl_ctx = NULL; | ||
1316 | SSL *ssl = NULL; | ||
1317 | int failure; | ||
1318 | CBB cbb; | ||
1319 | size_t dlen; | ||
1320 | uint8_t dummy[1234]; | ||
1321 | |||
1322 | failure = 1; | ||
1323 | |||
1324 | CBB_init(&cbb, 0); | ||
1325 | |||
1326 | /* Create fake session tickets with random data. */ | ||
1327 | arc4random_buf(tlsext_sessionticket_hello_min, | ||
1328 | sizeof(tlsext_sessionticket_hello_min)); | ||
1329 | arc4random_buf(tlsext_sessionticket_hello_max, | ||
1330 | sizeof(tlsext_sessionticket_hello_max)); | ||
1331 | |||
1332 | if ((ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) | ||
1333 | errx(1, "failed to create SSL_CTX"); | ||
1334 | if ((ssl = SSL_new(ssl_ctx)) == NULL) | ||
1335 | errx(1, "failed to create SSL"); | ||
1336 | |||
1337 | /* Should need a ticket by default. */ | ||
1338 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1339 | FAIL("clienthello should need Sessionticket for default " | ||
1340 | "ciphers\n"); | ||
1341 | goto err; | ||
1342 | } | ||
1343 | |||
1344 | /* Test disabling tickets. */ | ||
1345 | if ((SSL_set_options(ssl, SSL_OP_NO_TICKET) & SSL_OP_NO_TICKET) == 0) { | ||
1346 | FAIL("Cannot disable tickets in the TLS connection"); | ||
1347 | return 0; | ||
1348 | } | ||
1349 | if (tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1350 | FAIL("clienthello should not need SessionTicket if it was disabled"); | ||
1351 | goto err; | ||
1352 | } | ||
1353 | |||
1354 | /* Test re-enabling tickets. */ | ||
1355 | if ((SSL_clear_options(ssl, SSL_OP_NO_TICKET) & SSL_OP_NO_TICKET) != 0) { | ||
1356 | FAIL("Cannot re-enable tickets in the TLS connection"); | ||
1357 | return 0; | ||
1358 | } | ||
1359 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1360 | FAIL("clienthello should need SessionTicket if it was disabled"); | ||
1361 | goto err; | ||
1362 | } | ||
1363 | |||
1364 | /* Since we don't have a session, we should build an empty ticket. */ | ||
1365 | if (!tlsext_sessionticket_clienthello_build(ssl, &cbb)) { | ||
1366 | FAIL("Cannot build a ticket"); | ||
1367 | goto err; | ||
1368 | } | ||
1369 | if (!CBB_finish(&cbb, &data, &dlen)) { | ||
1370 | FAIL("Cannot finish CBB"); | ||
1371 | goto err; | ||
1372 | } | ||
1373 | if (dlen != 0) { | ||
1374 | FAIL("Expected 0 length but found %zu\n", dlen); | ||
1375 | goto err; | ||
1376 | } | ||
1377 | |||
1378 | CBB_cleanup(&cbb); | ||
1379 | CBB_init(&cbb, 0); | ||
1380 | free(data); | ||
1381 | data = NULL; | ||
1382 | |||
1383 | /* With a new session (but no ticket), we should still have 0 length */ | ||
1384 | if ((ssl->session = SSL_SESSION_new()) == NULL) | ||
1385 | errx(1, "failed to create session"); | ||
1386 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1387 | FAIL("Should still want a session ticket with a new session"); | ||
1388 | goto err; | ||
1389 | } | ||
1390 | if (!tlsext_sessionticket_clienthello_build(ssl, &cbb)) { | ||
1391 | FAIL("Cannot build a ticket"); | ||
1392 | goto err; | ||
1393 | } | ||
1394 | if (!CBB_finish(&cbb, &data, &dlen)) { | ||
1395 | FAIL("Cannot finish CBB"); | ||
1396 | goto err; | ||
1397 | } | ||
1398 | if (dlen != 0) { | ||
1399 | FAIL("Expected 0 length but found %zu\n", dlen); | ||
1400 | goto err; | ||
1401 | } | ||
1402 | |||
1403 | CBB_cleanup(&cbb); | ||
1404 | CBB_init(&cbb, 0); | ||
1405 | free(data); | ||
1406 | data = NULL; | ||
1407 | |||
1408 | /* With a new session (and ticket), we should use that ticket */ | ||
1409 | SSL_SESSION_free(ssl->session); | ||
1410 | if ((ssl->session = SSL_SESSION_new()) == NULL) | ||
1411 | errx(1, "failed to create session"); | ||
1412 | |||
1413 | arc4random_buf(&dummy, sizeof(dummy)); | ||
1414 | if ((ssl->session->tlsext_tick = malloc(sizeof(dummy))) == NULL) { | ||
1415 | errx(1, "failed to malloc"); | ||
1416 | } | ||
1417 | memcpy(ssl->session->tlsext_tick, dummy, sizeof(dummy)); | ||
1418 | ssl->session->tlsext_ticklen = sizeof(dummy); | ||
1419 | |||
1420 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1421 | FAIL("Should still want a session ticket with a new session"); | ||
1422 | goto err; | ||
1423 | } | ||
1424 | if (!tlsext_sessionticket_clienthello_build(ssl, &cbb)) { | ||
1425 | FAIL("Cannot build a ticket"); | ||
1426 | goto err; | ||
1427 | } | ||
1428 | if (!CBB_finish(&cbb, &data, &dlen)) { | ||
1429 | FAIL("Cannot finish CBB"); | ||
1430 | goto err; | ||
1431 | } | ||
1432 | if (dlen != sizeof(dummy)) { | ||
1433 | FAIL("Expected %zu length but found %zu\n", sizeof(dummy), dlen); | ||
1434 | goto err; | ||
1435 | } | ||
1436 | if (memcmp(data, dummy, dlen) != 0) { | ||
1437 | FAIL("serverhello SNI differs:\n"); | ||
1438 | compare_data(data, dlen, | ||
1439 | dummy, sizeof(dummy)); | ||
1440 | goto err; | ||
1441 | } | ||
1442 | |||
1443 | CBB_cleanup(&cbb); | ||
1444 | CBB_init(&cbb, 0); | ||
1445 | free(data); | ||
1446 | data = NULL; | ||
1447 | free(ssl->session->tlsext_tick); | ||
1448 | ssl->session->tlsext_tick = NULL; | ||
1449 | ssl->session->tlsext_ticklen = 0; | ||
1450 | |||
1451 | /* | ||
1452 | * Send in NULL to disable session tickets at runtime without going | ||
1453 | * through SSL_set_options(). | ||
1454 | */ | ||
1455 | if (!SSL_set_session_ticket_ext(ssl, NULL, 0)) { | ||
1456 | FAIL("Could not set a NULL custom ticket"); | ||
1457 | goto err; | ||
1458 | } | ||
1459 | /* Should not need a ticket in this case */ | ||
1460 | if (tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1461 | FAIL("Should not want to use session tickets with a NULL custom"); | ||
1462 | goto err; | ||
1463 | } | ||
1464 | |||
1465 | /* | ||
1466 | * If you want to remove the tlsext_session_ticket behavior, you have | ||
1467 | * to do it manually. | ||
1468 | */ | ||
1469 | free(ssl->internal->tlsext_session_ticket); | ||
1470 | ssl->internal->tlsext_session_ticket = NULL; | ||
1471 | |||
1472 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1473 | FAIL("Should need a session ticket again when the custom one is removed"); | ||
1474 | goto err; | ||
1475 | } | ||
1476 | |||
1477 | /* Test a custom session ticket (not recommended in practice) */ | ||
1478 | if (!SSL_set_session_ticket_ext(ssl, tlsext_sessionticket_hello_max, | ||
1479 | sizeof(tlsext_sessionticket_hello_max))) { | ||
1480 | FAIL("Should be able to set a custom ticket"); | ||
1481 | goto err; | ||
1482 | } | ||
1483 | if (!tlsext_sessionticket_clienthello_needs(ssl)) { | ||
1484 | FAIL("Should need a session ticket again when the custom one is not empty"); | ||
1485 | goto err; | ||
1486 | } | ||
1487 | if (!tlsext_sessionticket_clienthello_build(ssl, &cbb)) { | ||
1488 | FAIL("Cannot build a ticket with a max length random payload"); | ||
1489 | goto err; | ||
1490 | } | ||
1491 | if (!CBB_finish(&cbb, &data, &dlen)) { | ||
1492 | FAIL("Cannot finish CBB"); | ||
1493 | goto err; | ||
1494 | } | ||
1495 | if (dlen != sizeof(tlsext_sessionticket_hello_max)) { | ||
1496 | FAIL("Expected %zu length but found %zu\n", | ||
1497 | sizeof(tlsext_sessionticket_hello_max), dlen); | ||
1498 | goto err; | ||
1499 | } | ||
1500 | if (memcmp(data, tlsext_sessionticket_hello_max, | ||
1501 | sizeof(tlsext_sessionticket_hello_max)) != 0) { | ||
1502 | FAIL("Expected to get what we passed in"); | ||
1503 | compare_data(data, dlen, | ||
1504 | tlsext_sessionticket_hello_max, | ||
1505 | sizeof(tlsext_sessionticket_hello_max)); | ||
1506 | goto err; | ||
1507 | } | ||
1508 | |||
1509 | failure = 0; | ||
1510 | |||
1511 | err: | ||
1512 | CBB_cleanup(&cbb); | ||
1513 | SSL_CTX_free(ssl_ctx); | ||
1514 | SSL_free(ssl); | ||
1515 | free(data); | ||
1516 | |||
1517 | return (failure); | ||
1518 | } | ||
1519 | |||
1520 | |||
1521 | static int | ||
1522 | test_tlsext_sessionticket_serverhello(void) | ||
1523 | { | ||
1524 | SSL_CTX *ssl_ctx = NULL; | ||
1525 | SSL *ssl = NULL; | ||
1526 | int failure; | ||
1527 | uint8_t *data; | ||
1528 | size_t dlen; | ||
1529 | CBB cbb; | ||
1530 | |||
1531 | CBB_init(&cbb, 0); | ||
1532 | |||
1533 | failure = 1; | ||
1534 | |||
1535 | if ((ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) | ||
1536 | errx(1, "failed to create SSL_CTX"); | ||
1537 | if ((ssl = SSL_new(ssl_ctx)) == NULL) | ||
1538 | errx(1, "failed to create SSL"); | ||
1539 | |||
1540 | /* | ||
1541 | * By default, should not need a session ticket since the ticket | ||
1542 | * is not yet expected. | ||
1543 | */ | ||
1544 | if (tlsext_sessionticket_serverhello_needs(ssl)) { | ||
1545 | FAIL("serverhello should not need SessionTicket by default\n"); | ||
1546 | goto err; | ||
1547 | } | ||
1548 | |||
1549 | /* Test disabling tickets. */ | ||
1550 | if ((SSL_set_options(ssl, SSL_OP_NO_TICKET) & SSL_OP_NO_TICKET) == 0) { | ||
1551 | FAIL("Cannot disable tickets in the TLS connection"); | ||
1552 | return 0; | ||
1553 | } | ||
1554 | if (tlsext_sessionticket_serverhello_needs(ssl)) { | ||
1555 | FAIL("serverhello should not need SessionTicket if it was disabled"); | ||
1556 | goto err; | ||
1557 | } | ||
1558 | |||
1559 | /* Test re-enabling tickets. */ | ||
1560 | if ((SSL_clear_options(ssl, SSL_OP_NO_TICKET) & SSL_OP_NO_TICKET) != 0) { | ||
1561 | FAIL("Cannot re-enable tickets in the TLS connection"); | ||
1562 | return 0; | ||
1563 | } | ||
1564 | if (tlsext_sessionticket_serverhello_needs(ssl)) { | ||
1565 | FAIL("serverhello should not need SessionTicket yet"); | ||
1566 | goto err; | ||
1567 | } | ||
1568 | |||
1569 | /* Set expected to require it. */ | ||
1570 | ssl->internal->tlsext_ticket_expected = 1; | ||
1571 | if (!tlsext_sessionticket_serverhello_needs(ssl)) { | ||
1572 | FAIL("serverhello should now be required for SessionTicket"); | ||
1573 | goto err; | ||
1574 | } | ||
1575 | |||
1576 | /* server hello's session ticket should always be 0 length payload. */ | ||
1577 | if (!tlsext_sessionticket_serverhello_build(ssl, &cbb)) { | ||
1578 | FAIL("Cannot build a ticket with a max length random payload"); | ||
1579 | goto err; | ||
1580 | } | ||
1581 | if (!CBB_finish(&cbb, &data, &dlen)) { | ||
1582 | FAIL("Cannot finish CBB"); | ||
1583 | goto err; | ||
1584 | } | ||
1585 | if (dlen != 0) { | ||
1586 | FAIL("Expected 0 length but found %zu\n", dlen); | ||
1587 | goto err; | ||
1588 | } | ||
1589 | |||
1590 | failure = 0; | ||
1591 | |||
1592 | err: | ||
1593 | SSL_CTX_free(ssl_ctx); | ||
1594 | SSL_free(ssl); | ||
1595 | |||
1596 | return (failure); | ||
1597 | } | ||
1598 | |||
1301 | int | 1599 | int |
1302 | main(int argc, char **argv) | 1600 | main(int argc, char **argv) |
1303 | { | 1601 | { |
@@ -1317,5 +1615,8 @@ main(int argc, char **argv) | |||
1317 | failed |= test_tlsext_sni_clienthello(); | 1615 | failed |= test_tlsext_sni_clienthello(); |
1318 | failed |= test_tlsext_sni_serverhello(); | 1616 | failed |= test_tlsext_sni_serverhello(); |
1319 | 1617 | ||
1618 | failed |= test_tlsext_sessionticket_clienthello(); | ||
1619 | failed |= test_tlsext_sessionticket_serverhello(); | ||
1620 | |||
1320 | return (failed); | 1621 | return (failed); |
1321 | } | 1622 | } |