Skip to content

Commit

Permalink
Fix CVE-2022-3786 in punycode decoder.
Browse files Browse the repository at this point in the history
Fixed the ossl_a2ulabel() function which also contained a potential
buffer overflow, albeit without control of the contents.
This overflow could result in a crash (causing a denial of service).

The function also did not NUL-terminate the output in some cases.

The two issues fixed here were dentified and reported
by Viktor Dukhovni while researching CVE-2022-3602.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
  • Loading branch information
paulidale authored and t8m committed Nov 1, 2022
1 parent fe3b639 commit c42165b
Showing 1 changed file with 29 additions and 35 deletions.
64 changes: 29 additions & 35 deletions crypto/punycode.c
Expand Up @@ -123,7 +123,6 @@ int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
unsigned int bias = initial_bias;
size_t processed_in = 0, written_out = 0;
unsigned int max_out = *pout_length;

unsigned int basic_count = 0;
unsigned int loop;

Expand Down Expand Up @@ -185,7 +184,7 @@ int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
return 0;

memmove(pDecoded + i + 1, pDecoded + i,
(written_out - i) * sizeof *pDecoded);
(written_out - i) * sizeof(*pDecoded));
pDecoded[i] = n;
i++;
written_out++;
Expand Down Expand Up @@ -255,65 +254,61 @@ int ossl_a2ulabel(const char *in, char *out, size_t *outlen)
*/
char *outptr = out;
const char *inptr = in;
size_t size = 0;
size_t size = 0, maxsize;
int result = 1;

unsigned int i, j;
unsigned int buf[LABEL_BUF_SIZE]; /* It's a hostname */
if (out == NULL)

if (out == NULL) {
result = 0;
maxsize = 0;
} else {
maxsize = *outlen;
}

#define PUSHC(c) \
do \
if (size++ < maxsize) \
*outptr++ = c; \
else \
result = 0; \
while (0)

while (1) {
char *tmpptr = strchr(inptr, '.');
size_t delta = (tmpptr) ? (size_t)(tmpptr - inptr) : strlen(inptr);
size_t delta = tmpptr != NULL ? (size_t)(tmpptr - inptr) : strlen(inptr);

if (strncmp(inptr, "xn--", 4) != 0) {
size += delta + 1;

if (size >= *outlen - 1)
result = 0;

if (result > 0) {
memcpy(outptr, inptr, delta + 1);
outptr += delta + 1;
}
for (i = 0; i < delta + 1; i++)
PUSHC(inptr[i]);
} else {
unsigned int bufsize = LABEL_BUF_SIZE;
unsigned int i;

if (ossl_punycode_decode(inptr + 4, delta - 4, buf, &bufsize) <= 0)
return -1;

for (i = 0; i < bufsize; i++) {
unsigned char seed[6];
size_t utfsize = codepoint2utf8(seed, buf[i]);

if (utfsize == 0)
return -1;

size += utfsize;
if (size >= *outlen - 1)
result = 0;

if (result > 0) {
memcpy(outptr, seed, utfsize);
outptr += utfsize;
}
for (j = 0; j < utfsize; j++)
PUSHC(seed[j]);
}

if (tmpptr != NULL) {
*outptr = '.';
outptr++;
size++;
if (size >= *outlen - 1)
result = 0;
}
PUSHC(tmpptr != NULL ? '.' : '\0');
}

if (tmpptr == NULL)
break;

inptr = tmpptr + 1;
}
#undef PUSHC

*outlen = size;
return result;
}

Expand All @@ -327,12 +322,11 @@ int ossl_a2ulabel(const char *in, char *out, size_t *outlen)

int ossl_a2ucompare(const char *a, const char *u)
{
char a_ulabel[LABEL_BUF_SIZE];
char a_ulabel[LABEL_BUF_SIZE + 1];
size_t a_size = sizeof(a_ulabel);

if (ossl_a2ulabel(a, a_ulabel, &a_size) <= 0) {
if (ossl_a2ulabel(a, a_ulabel, &a_size) <= 0)
return -1;
}

return (strcmp(a_ulabel, u) == 0) ? 0 : 1;
return strcmp(a_ulabel, u) != 0;
}

0 comments on commit c42165b

Please sign in to comment.