diff options
Diffstat (limited to 'src/common/util_format.c')
-rw-r--r-- | src/common/util_format.c | 113 |
1 files changed, 43 insertions, 70 deletions
diff --git a/src/common/util_format.c b/src/common/util_format.c index aef9db85c8..e51757a4e8 100644 --- a/src/common/util_format.c +++ b/src/common/util_format.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,13 +22,16 @@ #include <stdlib.h> /* Return the base32 encoded size in bytes using the source length srclen. - * The NUL terminated byte is added as well since every base32 encoding - * requires enough space for it. */ + * + * (WATCH OUT: This API counts the terminating NUL byte, but + * base64_encode_size does not.) + */ size_t base32_encoded_size(size_t srclen) { size_t enclen; - enclen = CEIL_DIV(srclen*8, 5) + 1; + tor_assert(srclen < SIZE_T_CEILING / 8); + enclen = BASE32_NOPAD_BUFSIZE(srclen); tor_assert(enclen < INT_MAX && enclen > srclen); return enclen; } @@ -41,7 +44,6 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) size_t nbits = srclen * 8; size_t bit; - tor_assert(srclen < SIZE_T_CEILING/8); /* We need enough space for the encoded data and the extra NUL byte. */ tor_assert(base32_encoded_size(srclen) <= destlen); tor_assert(destlen < SIZE_T_CEILING); @@ -51,9 +53,10 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) for (i=0,bit=0; bit < nbits; ++i, bit+=5) { /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ - v = ((uint8_t)src[bit/8]) << 8; - if (bit+5<nbits) - v += (uint8_t)src[(bit/8)+1]; + size_t idx = bit / 8; + v = ((uint8_t)src[idx]) << 8; + if (idx+1 < srclen) + v += (uint8_t)src[idx+1]; /* set u to the 5-bit value at the bit'th bit of buf. */ u = (v >> (11-(bit%8))) & 0x1F; dest[i] = BASE32_CHARS[u]; @@ -133,6 +136,9 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) /** Return the Base64 encoded size of <b>srclen</b> bytes of data in * bytes. * + * (WATCH OUT: This API <em>does not</em> count the terminating NUL byte, + * but base32_encoded_size does.) + * * If <b>flags</b>&BASE64_ENCODE_MULTILINE is true, return the size * of the encoded output as multiline output (64 character, `\n' terminated * lines). @@ -141,19 +147,16 @@ size_t base64_encode_size(size_t srclen, int flags) { size_t enclen; + + /* Use INT_MAX for overflow checking because base64_encode() returns int. */ tor_assert(srclen < INT_MAX); + tor_assert(CEIL_DIV(srclen, 3) < INT_MAX / 4); - if (srclen == 0) - return 0; + enclen = BASE64_LEN(srclen); + if (flags & BASE64_ENCODE_MULTILINE) + enclen += CEIL_DIV(enclen, BASE64_OPENSSL_LINELEN); - enclen = ((srclen - 1) / 3) * 4 + 4; - if (flags & BASE64_ENCODE_MULTILINE) { - size_t remainder = enclen % BASE64_OPENSSL_LINELEN; - enclen += enclen / BASE64_OPENSSL_LINELEN; - if (remainder) - enclen++; - } - tor_assert(enclen < INT_MAX && enclen > srclen); + tor_assert(enclen < INT_MAX && (enclen == 0 || enclen > srclen)); return enclen; } @@ -263,10 +266,13 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, ENCODE_N(3); ENCODE_PAD(); break; + // LCOV_EXCL_START -- we can't reach this point, because we enforce + // 0 <= ncov_idx < 3 in the loop above. default: /* Something went catastrophically wrong. */ - tor_fragile_assert(); // LCOV_EXCL_LINE + tor_fragile_assert(); return -1; + // LCOV_EXCL_STOP } #undef ENCODE_N @@ -310,39 +316,6 @@ base64_encode_nopad(char *dest, size_t destlen, return (int)(out - dest); } -/** As base64_decode, but do not require any padding on the input */ -int -base64_decode_nopad(uint8_t *dest, size_t destlen, - const char *src, size_t srclen) -{ - if (srclen > SIZE_T_CEILING - 4) - return -1; - char *buf = tor_malloc(srclen + 4); - memcpy(buf, src, srclen+1); - size_t buflen; - switch (srclen % 4) - { - case 0: - default: - buflen = srclen; - break; - case 1: - tor_free(buf); - return -1; - case 2: - memcpy(buf+srclen, "==", 3); - buflen = srclen + 2; - break; - case 3: - memcpy(buf+srclen, "=", 2); - buflen = srclen + 1; - break; - } - int n = base64_decode((char*)dest, destlen, buf, buflen); - tor_free(buf); - return n; -} - #undef BASE64_OPENSSL_LINELEN /** @{ */ @@ -392,15 +365,9 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) const char *eos = src+srclen; uint32_t n=0; int n_idx=0; - char *dest_orig = dest; + size_t di = 0; - /* Max number of bits == srclen*6. - * Number of bytes required to hold all bits == (srclen*6)/8. - * Yes, we want to round down: anything that hangs over the end of a - * byte is padding. */ - if (destlen < (srclen*3)/4) - return -1; - if (destlen > SIZE_T_CEILING) + if (destlen > INT_MAX) return -1; /* Make sure we leave no uninitialized data in the destination buffer. */ @@ -428,9 +395,11 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) n = (n<<6) | v; if ((++n_idx) == 4) { /* We've accumulated 24 bits in n. Flush them. */ - *dest++ = (n>>16); - *dest++ = (n>>8) & 0xff; - *dest++ = (n) & 0xff; + if (destlen < 3 || di > destlen - 3) + return -1; + dest[di++] = (n>>16); + dest[di++] = (n>>8) & 0xff; + dest[di++] = (n) & 0xff; n_idx = 0; n = 0; } @@ -448,18 +417,21 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) return -1; case 2: /* 12 leftover bits: The last 4 are padding and the first 8 are data. */ - *dest++ = n >> 4; + if (destlen < 1 || di > destlen - 1) + return -1; + dest[di++] = n >> 4; break; case 3: /* 18 leftover bits: The last 2 are padding and the first 16 are data. */ - *dest++ = n >> 10; - *dest++ = n >> 2; + if (destlen < 2 || di > destlen - 2) + return -1; + dest[di++] = n >> 10; + dest[di++] = n >> 2; } - tor_assert((dest-dest_orig) <= (ssize_t)destlen); - tor_assert((dest-dest_orig) <= INT_MAX); + tor_assert(di <= destlen); - return (int)(dest-dest_orig); + return (int)di; } #undef X #undef SP @@ -475,7 +447,8 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen) const char *end; char *cp; - tor_assert(destlen >= srclen*2+1); + tor_assert(srclen < SIZE_T_CEILING / 2 - 1); + tor_assert(destlen >= BASE16_BUFSIZE(srclen)); tor_assert(destlen < SIZE_T_CEILING); /* Make sure we leave no uninitialized data in the destination buffer. */ |