diff options
| author | doug <> | 2017-08-12 21:17:03 +0000 |
|---|---|---|
| committer | doug <> | 2017-08-12 21:17:03 +0000 |
| commit | 57d8377dfdb1def39bfaf39a76b799989c4b8b15 (patch) | |
| tree | a6945bbfcf083598e38feabf2ece8ed3cbfaed2b | |
| parent | aa07f6851bbcb6c8ad4d78c02d2b5814864eaac1 (diff) | |
| download | openbsd-57d8377dfdb1def39bfaf39a76b799989c4b8b15.tar.gz openbsd-57d8377dfdb1def39bfaf39a76b799989c4b8b15.tar.bz2 openbsd-57d8377dfdb1def39bfaf39a76b799989c4b8b15.zip | |
Rewrite session ticket TLS extension handling using CBB/CBS and the new
extension framework.
ok jsing@ beck@
Diffstat (limited to '')
| -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 | } |
