diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libssl/ssl_tlsext.c | 85 | ||||
| -rw-r--r-- | src/regress/lib/libssl/tlsext/tlsexttest.c | 101 |
2 files changed, 173 insertions, 13 deletions
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c index e4ba549814..14cf6fce84 100644 --- a/src/lib/libssl/ssl_tlsext.c +++ b/src/lib/libssl/ssl_tlsext.c | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | /* $OpenBSD: ssl_tlsext.c,v 1.144 2024/03/27 10:44:17 beck Exp $ */ | 1 | /* $OpenBSD: ssl_tlsext.c,v 1.145 2024/03/27 22:27:09 beck Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> |
| 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
| 5 | * Copyright (c) 2018-2019 Bob Beck <beck@openbsd.org> | 5 | * Copyright (c) 2018-2019, 2024 Bob Beck <beck@openbsd.org> |
| 6 | * | 6 | * |
| 7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any |
| 8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -1464,14 +1464,65 @@ tlsext_keyshare_client_build(SSL *s, uint16_t msg_type, CBB *cbb) | |||
| 1464 | static int | 1464 | static int |
| 1465 | tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) | 1465 | tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) |
| 1466 | { | 1466 | { |
| 1467 | CBS client_shares, key_exchange; | 1467 | const uint16_t *client_groups = NULL, *server_groups = NULL; |
| 1468 | size_t client_groups_len = 0, server_groups_len = 0; | ||
| 1469 | size_t i, j, client_groups_index; | ||
| 1470 | int preferred_group_found = 0; | ||
| 1468 | int decode_error; | 1471 | int decode_error; |
| 1469 | uint16_t group; | 1472 | uint16_t group, client_preferred_group; |
| 1473 | CBS client_shares, key_exchange; | ||
| 1474 | |||
| 1475 | /* | ||
| 1476 | * RFC 8446 section 4.2.8: | ||
| 1477 | * | ||
| 1478 | * Each KeyShareEntry value MUST correspond to a group offered in the | ||
| 1479 | * "supported_groups" extension and MUST appear in the same order. | ||
| 1480 | * However, the values MAY be a non-contiguous subset of the | ||
| 1481 | * "supported_groups". | ||
| 1482 | */ | ||
| 1483 | |||
| 1484 | if (!tlsext_extension_seen(s, TLSEXT_TYPE_supported_groups)) { | ||
| 1485 | *alert = SSL_AD_ILLEGAL_PARAMETER; | ||
| 1486 | return 0; | ||
| 1487 | } | ||
| 1488 | if (!tlsext_extension_processed(s, TLSEXT_TYPE_supported_groups)) { | ||
| 1489 | *alert = SSL_AD_INTERNAL_ERROR; | ||
| 1490 | return 0; | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | /* | ||
| 1494 | * XXX similar to tls1_get_supported_group, but client pref | ||
| 1495 | * only - consider deduping later. | ||
| 1496 | */ | ||
| 1497 | /* | ||
| 1498 | * We are now assured of at least one client group. | ||
| 1499 | * Get the client and server group preference orders. | ||
| 1500 | */ | ||
| 1501 | tls1_get_group_list(s, 0, &server_groups, &server_groups_len); | ||
| 1502 | tls1_get_group_list(s, 1, &client_groups, &client_groups_len); | ||
| 1503 | |||
| 1504 | /* | ||
| 1505 | * Find the group that is most preferred by the client that | ||
| 1506 | * we also support. | ||
| 1507 | */ | ||
| 1508 | for (i = 0; i < client_groups_len && !preferred_group_found; i++) { | ||
| 1509 | if (!ssl_security_supported_group(s, client_groups[i])) | ||
| 1510 | continue; | ||
| 1511 | for (j = 0; j < server_groups_len; j++) { | ||
| 1512 | if (server_groups[j] == client_groups[i]) { | ||
| 1513 | client_preferred_group = client_groups[i]; | ||
| 1514 | preferred_group_found = 1; | ||
| 1515 | break; | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | } | ||
| 1470 | 1519 | ||
| 1471 | if (!CBS_get_u16_length_prefixed(cbs, &client_shares)) | 1520 | if (!CBS_get_u16_length_prefixed(cbs, &client_shares)) |
| 1472 | return 0; | 1521 | return 0; |
| 1473 | 1522 | ||
| 1523 | client_groups_index = 0; | ||
| 1474 | while (CBS_len(&client_shares) > 0) { | 1524 | while (CBS_len(&client_shares) > 0) { |
| 1525 | int client_sent_group; | ||
| 1475 | 1526 | ||
| 1476 | /* Unpack client share. */ | 1527 | /* Unpack client share. */ |
| 1477 | if (!CBS_get_u16(&client_shares, &group)) | 1528 | if (!CBS_get_u16(&client_shares, &group)) |
| @@ -1480,9 +1531,21 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) | |||
| 1480 | return 0; | 1531 | return 0; |
| 1481 | 1532 | ||
| 1482 | /* | 1533 | /* |
| 1483 | * XXX - check key exchange against supported groups from client. | 1534 | * Ensure the client share group was sent in supported groups, |
| 1484 | * XXX - check that groups only appear once. | 1535 | * and was sent in the same order as supported groups. The |
| 1536 | * supported groups has already been checked for duplicates. | ||
| 1485 | */ | 1537 | */ |
| 1538 | client_sent_group = 0; | ||
| 1539 | while (client_groups_index < client_groups_len) { | ||
| 1540 | if (group == client_groups[client_groups_index++]) { | ||
| 1541 | client_sent_group = 1; | ||
| 1542 | break; | ||
| 1543 | } | ||
| 1544 | } | ||
| 1545 | if (!client_sent_group) { | ||
| 1546 | *alert = SSL_AD_ILLEGAL_PARAMETER; | ||
| 1547 | return 0; | ||
| 1548 | } | ||
| 1486 | 1549 | ||
| 1487 | /* | 1550 | /* |
| 1488 | * Ignore this client share if we're using earlier than TLSv1.3 | 1551 | * Ignore this client share if we're using earlier than TLSv1.3 |
| @@ -1493,8 +1556,14 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) | |||
| 1493 | if (s->s3->hs.key_share != NULL) | 1556 | if (s->s3->hs.key_share != NULL) |
| 1494 | continue; | 1557 | continue; |
| 1495 | 1558 | ||
| 1496 | /* XXX - consider implementing server preference. */ | 1559 | /* |
| 1497 | if (!tls1_check_group(s, group)) | 1560 | * Ignore this client share if it is not for the most client |
| 1561 | * preferred supported group. This avoids a potential downgrade | ||
| 1562 | * situation where the client sends a client share for something | ||
| 1563 | * less preferred, and we choose to to use it instead of | ||
| 1564 | * requesting the more preferred group. | ||
| 1565 | */ | ||
| 1566 | if (!preferred_group_found || group != client_preferred_group) | ||
| 1498 | continue; | 1567 | continue; |
| 1499 | 1568 | ||
| 1500 | /* Decode and store the selected key share. */ | 1569 | /* Decode and store the selected key share. */ |
diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c index c7983833dc..e61722542e 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.86 2024/03/26 02:43:56 beck Exp $ */ | 1 | /* $OpenBSD: tlsexttest.c,v 1.87 2024/03/27 22:27:09 beck 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> |
| @@ -1109,7 +1109,6 @@ test_tlsext_ecpf_client(void) | |||
| 1109 | goto err; | 1109 | goto err; |
| 1110 | } | 1110 | } |
| 1111 | 1111 | ||
| 1112 | |||
| 1113 | failure = 0; | 1112 | failure = 0; |
| 1114 | 1113 | ||
| 1115 | err: | 1114 | err: |
| @@ -3648,6 +3647,7 @@ test_tlsext_keyshare_client(void) | |||
| 3648 | const struct tls_extension_funcs *server_funcs; | 3647 | const struct tls_extension_funcs *server_funcs; |
| 3649 | int failure; | 3648 | int failure; |
| 3650 | size_t dlen; | 3649 | size_t dlen; |
| 3650 | size_t idx; | ||
| 3651 | int alert; | 3651 | int alert; |
| 3652 | CBB cbb; | 3652 | CBB cbb; |
| 3653 | CBS cbs; | 3653 | CBS cbs; |
| @@ -3701,18 +3701,109 @@ test_tlsext_keyshare_client(void) | |||
| 3701 | goto done; | 3701 | goto done; |
| 3702 | } | 3702 | } |
| 3703 | 3703 | ||
| 3704 | (ssl)->version = TLS1_3_VERSION; | 3704 | ssl->version = TLS1_3_VERSION; |
| 3705 | CBS_init(&cbs, data, dlen); | 3705 | |
| 3706 | /* Fake up the ssl enough so the key share can process */ | ||
| 3707 | ssl->session = SSL_SESSION_new(); | ||
| 3708 | ssl->s3 = calloc(1, sizeof(*ssl->s3)); | ||
| 3709 | ssl->session->tlsext_supportedgroups = calloc(4, | ||
| 3710 | sizeof(unsigned short)); | ||
| 3711 | if (ssl->session == NULL || ssl->s3 == NULL || | ||
| 3712 | ssl->session->tlsext_supportedgroups == NULL) { | ||
| 3713 | FAIL("malloc"); | ||
| 3714 | goto done; | ||
| 3715 | } | ||
| 3716 | ssl->session->tlsext_supportedgroups[0] = 29; | ||
| 3717 | ssl->session->tlsext_supportedgroups[1] = 23; | ||
| 3718 | ssl->session->tlsext_supportedgroups[2] = 24; | ||
| 3719 | ssl->session->tlsext_supportedgroups[3] = 25; | ||
| 3720 | ssl->session->tlsext_supportedgroups_length = 4; | ||
| 3721 | tls_extension_find(TLSEXT_TYPE_supported_groups, &idx); | ||
| 3722 | ssl->s3->hs.extensions_processed |= (1 << idx); | ||
| 3723 | ssl->s3->hs.extensions_seen |= (1 << idx); | ||
| 3724 | ssl->s3->hs.our_max_tls_version = TLS1_3_VERSION; | ||
| 3706 | 3725 | ||
| 3726 | /* | ||
| 3727 | * We should select the key share for group 29, when group 29 | ||
| 3728 | * is the most preferred group | ||
| 3729 | */ | ||
| 3730 | CBS_init(&cbs, data, dlen); | ||
| 3707 | if (!server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { | 3731 | if (!server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { |
| 3708 | FAIL("failed to parse client keyshare\n"); | 3732 | FAIL("failed to process client keyshare\n"); |
| 3733 | goto done; | ||
| 3734 | } | ||
| 3735 | if (CBS_len(&cbs) != 0) { | ||
| 3736 | FAIL("extension data remaining\n"); | ||
| 3737 | goto done; | ||
| 3738 | } | ||
| 3739 | if (ssl->s3->hs.key_share == NULL) { | ||
| 3740 | FAIL("Did not select a key share"); | ||
| 3709 | goto done; | 3741 | goto done; |
| 3710 | } | 3742 | } |
| 3711 | 3743 | ||
| 3744 | /* | ||
| 3745 | * Pretend the client did not send the supported groups extension. We | ||
| 3746 | * should fail to process. | ||
| 3747 | */ | ||
| 3748 | ssl->s3->hs.extensions_seen = 0; | ||
| 3749 | free(ssl->s3->hs.key_share); | ||
| 3750 | ssl->s3->hs.key_share = NULL; | ||
| 3751 | CBS_init(&cbs, data, dlen); | ||
| 3752 | if (server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { | ||
| 3753 | FAIL("Processed key share when supported groups not provided"); | ||
| 3754 | goto done; | ||
| 3755 | } | ||
| 3756 | ssl->s3->hs.extensions_seen |= (1 << idx); | ||
| 3757 | |||
| 3758 | /* | ||
| 3759 | * Pretend supported groups did not get processed. We should fail to | ||
| 3760 | * process | ||
| 3761 | */ | ||
| 3762 | ssl->s3->hs.extensions_processed = 0; | ||
| 3763 | ssl->s3->hs.key_share = NULL; | ||
| 3764 | CBS_init(&cbs, data, dlen); | ||
| 3765 | if (server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { | ||
| 3766 | FAIL("Processed key share when supported groups unprocesed"); | ||
| 3767 | goto done; | ||
| 3768 | } | ||
| 3769 | ssl->s3->hs.extensions_processed |= (1 << idx); | ||
| 3770 | |||
| 3771 | /* | ||
| 3772 | * Remove group 29 by making it 0xbeef, meaning 29 has not been sent in | ||
| 3773 | * supported groups. This should fail to process. | ||
| 3774 | */ | ||
| 3775 | ssl->session->tlsext_supportedgroups[0] = 0xbeef; | ||
| 3776 | ssl->s3->hs.key_share = NULL; | ||
| 3777 | CBS_init(&cbs, data, dlen); | ||
| 3778 | if (server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { | ||
| 3779 | FAIL("Processed key share with invalid group!"); | ||
| 3780 | goto done; | ||
| 3781 | } | ||
| 3782 | ssl->session->tlsext_supportedgroups[0] = 29; | ||
| 3783 | |||
| 3784 | /* | ||
| 3785 | * Make 29 least preferred, while server supports both 29 and 25. | ||
| 3786 | * Client key share is for 29 but it prefers 25. We should successfully | ||
| 3787 | * process, but should not select this key share. | ||
| 3788 | */ | ||
| 3789 | ssl->session->tlsext_supportedgroups[0] = 25; | ||
| 3790 | ssl->session->tlsext_supportedgroups[3] = 29; | ||
| 3791 | ssl->s3->hs.key_share = NULL; | ||
| 3792 | CBS_init(&cbs, data, dlen); | ||
| 3793 | if (!server_funcs->process(ssl, SSL_TLSEXT_MSG_CH, &cbs, &alert)) { | ||
| 3794 | FAIL("failed to process client keyshare\n"); | ||
| 3795 | goto done; | ||
| 3796 | } | ||
| 3712 | if (CBS_len(&cbs) != 0) { | 3797 | if (CBS_len(&cbs) != 0) { |
| 3713 | FAIL("extension data remaining\n"); | 3798 | FAIL("extension data remaining\n"); |
| 3714 | goto done; | 3799 | goto done; |
| 3715 | } | 3800 | } |
| 3801 | if (ssl->s3->hs.key_share != NULL) { | ||
| 3802 | FAIL("Selected a key share when I should not have!"); | ||
| 3803 | goto done; | ||
| 3804 | } | ||
| 3805 | ssl->session->tlsext_supportedgroups[0] = 29; | ||
| 3806 | ssl->session->tlsext_supportedgroups[3] = 25; | ||
| 3716 | 3807 | ||
| 3717 | failure = 0; | 3808 | failure = 0; |
| 3718 | 3809 | ||
