Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/openssl/openssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPauli <pauli@openssl.org>2022-10-27 02:22:47 +0300
committerTomas Mraz <tomas@openssl.org>2022-11-01 19:44:49 +0300
commit680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 (patch)
tree7f44cceb29e258b862c0334b35f5a9d62b312c13
parent3b421ebc64c7b52f1b9feb3812bdc7781c784332 (diff)
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> (cherry picked from commit c42165b5706e42f67ef8ef4c351a9a4c5d21639a)
-rw-r--r--crypto/punycode.c64
1 files changed, 29 insertions, 35 deletions
diff --git a/crypto/punycode.c b/crypto/punycode.c
index f0796163e3..f55e351f7a 100644
--- a/crypto/punycode.c
+++ b/crypto/punycode.c
@@ -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;
@@ -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++;
@@ -255,30 +254,35 @@ 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 (!HAS_PREFIX(inptr, "xn--")) {
- 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;
@@ -286,26 +290,15 @@ int ossl_a2ulabel(const char *in, char *out, size_t *outlen)
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)
@@ -313,7 +306,9 @@ int ossl_a2ulabel(const char *in, char *out, size_t *outlen)
inptr = tmpptr + 1;
}
+#undef PUSHC
+ *outlen = size;
return result;
}
@@ -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;
}