Skip to content

Commit cf6f91f

Browse files
committed
Fix SSL_select_next_proto
Ensure that the provided client list is non-NULL and starts with a valid entry. When called from the ALPN callback the client list should already have been validated by OpenSSL so this should not cause a problem. When called from the NPN callback the client list is locally configured and will not have already been validated. Therefore SSL_select_next_proto should not assume that it is correctly formatted. We implement stricter checking of the client protocol list. We also do the same for the server list while we are about it. CVE-2024-5535 Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from #24718) (cherry picked from commit 4ada436)
1 parent a6facb1 commit cf6f91f

File tree

1 file changed

+40
-23
lines changed

1 file changed

+40
-23
lines changed

ssl/ssl_lib.c

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,37 +2952,54 @@ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
29522952
unsigned int server_len,
29532953
const unsigned char *client, unsigned int client_len)
29542954
{
2955-
unsigned int i, j;
2956-
const unsigned char *result;
2957-
int status = OPENSSL_NPN_UNSUPPORTED;
2955+
PACKET cpkt, csubpkt, spkt, ssubpkt;
2956+
2957+
if (!PACKET_buf_init(&cpkt, client, client_len)
2958+
|| !PACKET_get_length_prefixed_1(&cpkt, &csubpkt)
2959+
|| PACKET_remaining(&csubpkt) == 0) {
2960+
*out = NULL;
2961+
*outlen = 0;
2962+
return OPENSSL_NPN_NO_OVERLAP;
2963+
}
2964+
2965+
/*
2966+
* Set the default opportunistic protocol. Will be overwritten if we find
2967+
* a match.
2968+
*/
2969+
*out = (unsigned char *)PACKET_data(&csubpkt);
2970+
*outlen = (unsigned char)PACKET_remaining(&csubpkt);
29582971

29592972
/*
29602973
* For each protocol in server preference order, see if we support it.
29612974
*/
2962-
for (i = 0; i < server_len;) {
2963-
for (j = 0; j < client_len;) {
2964-
if (server[i] == client[j] &&
2965-
memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) {
2966-
/* We found a match */
2967-
result = &server[i];
2968-
status = OPENSSL_NPN_NEGOTIATED;
2969-
goto found;
2975+
if (PACKET_buf_init(&spkt, server, server_len)) {
2976+
while (PACKET_get_length_prefixed_1(&spkt, &ssubpkt)) {
2977+
if (PACKET_remaining(&ssubpkt) == 0)
2978+
continue; /* Invalid - ignore it */
2979+
if (PACKET_buf_init(&cpkt, client, client_len)) {
2980+
while (PACKET_get_length_prefixed_1(&cpkt, &csubpkt)) {
2981+
if (PACKET_equal(&csubpkt, PACKET_data(&ssubpkt),
2982+
PACKET_remaining(&ssubpkt))) {
2983+
/* We found a match */
2984+
*out = (unsigned char *)PACKET_data(&ssubpkt);
2985+
*outlen = (unsigned char)PACKET_remaining(&ssubpkt);
2986+
return OPENSSL_NPN_NEGOTIATED;
2987+
}
2988+
}
2989+
/* Ignore spurious trailing bytes in the client list */
2990+
} else {
2991+
/* This should never happen */
2992+
return OPENSSL_NPN_NO_OVERLAP;
29702993
}
2971-
j += client[j];
2972-
j++;
29732994
}
2974-
i += server[i];
2975-
i++;
2995+
/* Ignore spurious trailing bytes in the server list */
29762996
}
29772997

2978-
/* There's no overlap between our protocols and the server's list. */
2979-
result = client;
2980-
status = OPENSSL_NPN_NO_OVERLAP;
2981-
2982-
found:
2983-
*out = (unsigned char *)result + 1;
2984-
*outlen = result[0];
2985-
return status;
2998+
/*
2999+
* There's no overlap between our protocols and the server's list. We use
3000+
* the default opportunistic protocol selected earlier
3001+
*/
3002+
return OPENSSL_NPN_NO_OVERLAP;
29863003
}
29873004

29883005
#ifndef OPENSSL_NO_NEXTPROTONEG

0 commit comments

Comments
 (0)