Skip to content

Commit c42165b

Browse files
paulidalet8m
authored andcommitted
Fix CVE-2022-3786 in punycode decoder.
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>
1 parent fe3b639 commit c42165b

File tree

1 file changed

+29
-35
lines changed

1 file changed

+29
-35
lines changed

crypto/punycode.c

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
123123
unsigned int bias = initial_bias;
124124
size_t processed_in = 0, written_out = 0;
125125
unsigned int max_out = *pout_length;
126-
127126
unsigned int basic_count = 0;
128127
unsigned int loop;
129128

@@ -185,7 +184,7 @@ int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
185184
return 0;
186185

187186
memmove(pDecoded + i + 1, pDecoded + i,
188-
(written_out - i) * sizeof *pDecoded);
187+
(written_out - i) * sizeof(*pDecoded));
189188
pDecoded[i] = n;
190189
i++;
191190
written_out++;
@@ -255,65 +254,61 @@ int ossl_a2ulabel(const char *in, char *out, size_t *outlen)
255254
*/
256255
char *outptr = out;
257256
const char *inptr = in;
258-
size_t size = 0;
257+
size_t size = 0, maxsize;
259258
int result = 1;
260-
259+
unsigned int i, j;
261260
unsigned int buf[LABEL_BUF_SIZE]; /* It's a hostname */
262-
if (out == NULL)
261+
262+
if (out == NULL) {
263263
result = 0;
264+
maxsize = 0;
265+
} else {
266+
maxsize = *outlen;
267+
}
268+
269+
#define PUSHC(c) \
270+
do \
271+
if (size++ < maxsize) \
272+
*outptr++ = c; \
273+
else \
274+
result = 0; \
275+
while (0)
264276

265277
while (1) {
266278
char *tmpptr = strchr(inptr, '.');
267-
size_t delta = (tmpptr) ? (size_t)(tmpptr - inptr) : strlen(inptr);
279+
size_t delta = tmpptr != NULL ? (size_t)(tmpptr - inptr) : strlen(inptr);
268280

269281
if (strncmp(inptr, "xn--", 4) != 0) {
270-
size += delta + 1;
271-
272-
if (size >= *outlen - 1)
273-
result = 0;
274-
275-
if (result > 0) {
276-
memcpy(outptr, inptr, delta + 1);
277-
outptr += delta + 1;
278-
}
282+
for (i = 0; i < delta + 1; i++)
283+
PUSHC(inptr[i]);
279284
} else {
280285
unsigned int bufsize = LABEL_BUF_SIZE;
281-
unsigned int i;
282286

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

286290
for (i = 0; i < bufsize; i++) {
287291
unsigned char seed[6];
288292
size_t utfsize = codepoint2utf8(seed, buf[i]);
293+
289294
if (utfsize == 0)
290295
return -1;
291296

292-
size += utfsize;
293-
if (size >= *outlen - 1)
294-
result = 0;
295-
296-
if (result > 0) {
297-
memcpy(outptr, seed, utfsize);
298-
outptr += utfsize;
299-
}
297+
for (j = 0; j < utfsize; j++)
298+
PUSHC(seed[j]);
300299
}
301300

302-
if (tmpptr != NULL) {
303-
*outptr = '.';
304-
outptr++;
305-
size++;
306-
if (size >= *outlen - 1)
307-
result = 0;
308-
}
301+
PUSHC(tmpptr != NULL ? '.' : '\0');
309302
}
310303

311304
if (tmpptr == NULL)
312305
break;
313306

314307
inptr = tmpptr + 1;
315308
}
309+
#undef PUSHC
316310

311+
*outlen = size;
317312
return result;
318313
}
319314

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

328323
int ossl_a2ucompare(const char *a, const char *u)
329324
{
330-
char a_ulabel[LABEL_BUF_SIZE];
325+
char a_ulabel[LABEL_BUF_SIZE + 1];
331326
size_t a_size = sizeof(a_ulabel);
332327

333-
if (ossl_a2ulabel(a, a_ulabel, &a_size) <= 0) {
328+
if (ossl_a2ulabel(a, a_ulabel, &a_size) <= 0)
334329
return -1;
335-
}
336330

337-
return (strcmp(a_ulabel, u) == 0) ? 0 : 1;
331+
return strcmp(a_ulabel, u) != 0;
338332
}

0 commit comments

Comments
 (0)