Based on,

commit dd46b5417809647f561d8a5e0e74c3aacd235258
Author: Amos Jeffries <yadij@users.noreply.github.com>
Date:   2019-05-21 21:31:31 +0000

    Replace uudecode with libnettle base64 decoder (#406)
    
    Since RFC 7235 updated the HTTP Authentication credentials token
    to the token68 characterset it is possible that characters
    uudecode cannot cope with are received.
    
    The Nettle decoder better handles characters which are valid but
    not to be used for Basic auth token.


commit aadbbd7d080ef1662bfd7ea568edbb29f25fdd72
Author: Amos Jeffries <squid3@treenet.co.nz>
Date:   Tue Dec 30 01:09:27 2014 -0800

    Crypto-NG: Base64 crypto replacement
    
    The existing Squid base64 code had ambiguous copyright licensing. In
    particular it only referenced a dead URL for source copyright
    ownership details. In all likelihood this was for an Open Source
    implementation, but we dont have sufficient record of the original
    license terms to be certain without a long investigation.
    
    It has also been heavily modified and customized over the decades
    since importing whih complicates the issue a lot.
    
    It also does not match any of the common industry context-based API
    patterns for encoders/decoders.
    
    
    This patch replaces that logic with GPLv2 licensed code from the
    Nettle crypto library. Either linking the library dynamically or in
    its absence embedding the logic via our libmiscencoding library.
    
    It also updates all code to the new API, and as a byproduct removes
    several layers of deprecated wrapper functions which have grown in
    over the years.

commit 18db38a81d6c43efeaa3aa0fefde3ff17516ccbc
Author: Markus Moeller <huaraz@moeller.plus.com>
Date:   Mon Jan 5 01:57:06 2015 -0800

    negotiate_kerberos_auth: fix token decode typo in rev.13785


Index: squid-3.5.21/include/uudecode.h
===================================================================
--- squid-3.5.21.orig/include/uudecode.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef _SQUID_UUDECODE_H
-#define _SQUID_UUDECODE_H
-
-#ifdef __cplusplus
-extern "C"
-#else
-extern
-#endif
-
-char *uudecode(const char *);
-
-#endif /* _SQUID_UUDECODE_H */
-
Index: squid-3.5.21/lib/Makefile.am
===================================================================
--- squid-3.5.21.orig/lib/Makefile.am
+++ squid-3.5.21/lib/Makefile.am
@@ -58,8 +58,7 @@ libmiscencoding_la_SOURCES = \
 	html_quote.c \
 	md5.c \
 	rfc1738.c \
-	rfc2617.c \
-	uudecode.c
+	rfc2617.c
 
 libmisccontainers_la_SOURCES = \
 	hash.cc
Index: squid-3.5.21/lib/uudecode.c
===================================================================
--- squid-3.5.21.orig/lib/uudecode.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-#include "uudecode.h"
-
-/* aaaack but it's fast and const should make it shared text page. */
-const int pr2six[256] = {
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
-    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27,
-    28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
-};
-
-char *
-uudecode(const char *bufcoded)
-{
-    int nbytesdecoded;
-    const unsigned char *bufin;
-    char *bufplain;
-    unsigned char *bufout;
-    int nprbytes;
-
-    /* Strip leading whitespace. */
-
-    while (*bufcoded == ' ' || *bufcoded == '\t')
-        bufcoded++;
-
-    /* Figure out how many characters are in the input buffer.
-     * Allocate this many from the per-transaction pool for the result.
-     */
-    bufin = (const unsigned char *) bufcoded;
-    while (pr2six[*(bufin++)] <= 63);
-    nprbytes = (const char *) bufin - bufcoded - 1;
-    nbytesdecoded = ((nprbytes + 3) / 4) * 3;
-
-    bufplain = xmalloc(nbytesdecoded + 1);
-    bufout = (unsigned char *) bufplain;
-    bufin = (const unsigned char *) bufcoded;
-
-    while (nprbytes > 0) {
-        *(bufout++) =
-            (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
-        *(bufout++) =
-            (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
-        *(bufout++) =
-            (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
-        bufin += 4;
-        nprbytes -= 4;
-    }
-
-    if (nprbytes & 03) {
-        if (pr2six[bufin[-2]] > 63)
-            nbytesdecoded -= 2;
-        else
-            nbytesdecoded -= 1;
-    }
-    bufplain[nbytesdecoded] = '\0';
-    return bufplain;
-}
-
Index: squid-3.5.21/src/auth/basic/Config.cc
===================================================================
--- squid-3.5.21.orig/src/auth/basic/Config.cc
+++ squid-3.5.21/src/auth/basic/Config.cc
@@ -19,6 +19,7 @@
 #include "auth/basic/UserRequest.h"
 #include "auth/Gadgets.h"
 #include "auth/State.h"
+#include "base64.h"
 #include "cache_cf.h"
 #include "charset.h"
 #include "helper.h"
@@ -28,7 +29,6 @@
 #include "rfc1738.h"
 #include "SquidTime.h"
 #include "Store.h"
-#include "uudecode.h"
 #include "wordlist.h"
 
 /* Basic Scheme */
@@ -166,10 +166,17 @@ Auth::Basic::Config::decodeCleartext(con
     // XXX: really? is the \n actually still there? does the header parse not drop it?
     char *eek = xstrdup(proxy_auth);
     strtok(eek, "\n");
-    char *cleartext = uudecode(eek);
-    safe_free(eek);
 
-    if (cleartext) {
+    const size_t srcLen = strlen(eek);
+    char *cleartext = static_cast<char*>(xmalloc(BASE64_DECODE_LENGTH(srcLen)+1));
+
+    struct base64_decode_ctx ctx;
+    base64_decode_init(&ctx);
+
+    unsigned int dstLen = 0;
+    if (base64_decode_update(&ctx, &dstLen, reinterpret_cast<uint8_t*>(cleartext), srcLen, (const uint8_t*)eek) && base64_decode_final(&ctx)) {
+        cleartext[dstLen] = '\0';
+
         /*
          * Don't allow NL or CR in the credentials.
          * Oezguer Kesim <oec@codeblau.de>
@@ -180,7 +187,12 @@ Auth::Basic::Config::decodeCleartext(con
             debugs(29, DBG_IMPORTANT, "WARNING: Bad characters in authorization header '" << httpAuthHeader << "'");
             safe_free(cleartext);
         }
+    } else {
+        debugs(29, 2, "WARNING: Invalid Base64 character in authorization header '" << httpAuthHeader << "'");
+        safe_free(cleartext);
     }
+
+    safe_free(eek);
     return cleartext;
 }
 
Index: squid-3.5.21/include/base64.h
===================================================================
--- squid-3.5.21.orig/include/base64.h
+++ squid-3.5.21/include/base64.h
@@ -9,6 +9,14 @@
 #ifndef _SQUID_BASE64_H
 #define _SQUID_BASE64_H
 
+#include <nettle/base64.h>
+
+/// Calculate the buffer size required to hold the encoded form of
+/// a string of length 'decodedLen' including all terminator bytes.
+#define base64_encode_len(length) (BASE64_ENCODE_LENGTH(length)+BASE64_ENCODE_FINAL_LENGTH+1)
+
+#if 0
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -56,5 +64,6 @@ extern const char *old_base64_encode(con
 #ifdef __cplusplus
 }
 #endif
+#endif // libnettle
 #endif /* _SQUID_BASE64_H */
 
Index: squid-3.5.21/configure.ac
===================================================================
--- squid-3.5.21.orig/configure.ac
+++ squid-3.5.21/configure.ac
@@ -1231,7 +1231,7 @@ case "$with_nettle" in
 if test "x$with_nettle" != "xno" ; then
   AC_CHECK_LIB(nettle, nettle_md5_init,[
     NETTLELIB="$NETTLELIBDIR -lnettle"
-    AC_CHECK_HEADERS(nettle/md5.h)
+    AC_CHECK_HEADERS(nettle/md5.h nettle/base64.h)
   ],[with_nettle=no])
 fi
 AC_MSG_NOTICE([Using Nettle cryptographic library: ${with_nettle:=yes}])
Index: squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
===================================================================
--- squid-3.5.21.orig/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
+++ squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
@@ -658,12 +658,23 @@ main(int argc, char *const argv[])
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        input_token.length = (size_t)base64_decode_len(buf+3);
-        debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
-              LogTime(), PROGRAM, buf + 3, (int) input_token.length);
+	const uint8_t *b64Token = reinterpret_cast<const uint8_t*>(buf+3);
+	const size_t srcLen = strlen(buf+3);
+        input_token.length = BASE64_DECODE_LENGTH(srcLen);
+        debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length estimate: %d).\n",
+              LogTime(), PROGRAM, b64Token, (int) input_token.length);
         input_token.value = xmalloc(input_token.length);
 
-        input_token.length = (size_t)base64_decode((char *) input_token.value, (unsigned int)input_token.length, buf+3);
+        struct base64_decode_ctx ctx;
+        base64_decode_init(&ctx);
+        unsigned int dstLen = 0;
+        if (!base64_decode_update(&ctx, &dstLen, static_cast<uint8_t*>(input_token.value), srcLen, b64Token) ||
+                !base64_decode_final(&ctx)) {
+            debug((char *) "%s| %s: ERROR: Invalid base64 token [%s]\n", LogTime(), PROGRAM, b64Token);
+            fprintf(stdout, "BH Invalid negotiate request token\n");
+            continue;
+        }
+        input_token.length = dstLen;
 
         if ((input_token.length >= sizeof ntlmProtocol + 1) &&
                 (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
@@ -710,14 +721,17 @@ main(int argc, char *const argv[])
         if (output_token.length) {
             spnegoToken = (const unsigned char *) output_token.value;
             spnegoTokenLength = output_token.length;
-            token = (char *) xmalloc((size_t)base64_encode_len((int)spnegoTokenLength));
+            token = (char *) xmalloc((size_t)base64_encode_len(spnegoTokenLength));
             if (token == NULL) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
-            base64_encode_str(token, base64_encode_len((int)spnegoTokenLength),
-                              (const char *) spnegoToken, (int)spnegoTokenLength);
+            struct base64_encode_ctx tokCtx;
+            base64_encode_init(&tokCtx);
+            size_t blen = base64_encode_update(&tokCtx, reinterpret_cast<uint8_t*>(token), spnegoTokenLength, reinterpret_cast<const uint8_t*>(spnegoToken));
+            blen += base64_encode_final(&tokCtx, reinterpret_cast<uint8_t*>(token)+blen);
+            token[blen] = '\0';
 
             if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log, 1))
                 goto cleanup;
Index: squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc
===================================================================
--- squid-3.5.21.orig/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc
+++ squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc
@@ -189,26 +189,24 @@ squid_kerb_proxy_auth(char *proxy)
     major_status = gss_import_name(&minor_status, &service,
                                    gss_nt_service_name, &server_name);
 
-    if (check_gss_err(major_status, minor_status, "gss_import_name()"))
-        goto cleanup;
+    if (!check_gss_err(major_status, minor_status, "gss_import_name()")) {
+        major_status = gss_init_sec_context(&minor_status,
+                                            GSS_C_NO_CREDENTIAL, &gss_context, server_name,
+                                            gss_mech_spnego,
+                                            0,
+                                            0,
+                                            GSS_C_NO_CHANNEL_BINDINGS,
+                                            &input_token, NULL, &output_token, NULL, NULL);
 
-    major_status = gss_init_sec_context(&minor_status,
-                                        GSS_C_NO_CREDENTIAL, &gss_context, server_name,
-                                        gss_mech_spnego,
-                                        0,
-                                        0,
-                                        GSS_C_NO_CHANNEL_BINDINGS,
-                                        &input_token, NULL, &output_token, NULL, NULL);
-
-    if (check_gss_err(major_status, minor_status, "gss_init_sec_context()"))
-        goto cleanup;
-
-    if (output_token.length) {
-        token = (char *) xmalloc((size_t)base64_encode_len((int)output_token.length));
-        base64_encode_str(token, base64_encode_len((int)output_token.length),
-                          (const char *) output_token.value, (int)output_token.length);
+        if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()") && output_token.length) {
+            token = (char *) xcalloc(base64_encode_len(output_token.length), 1);
+            struct base64_encode_ctx ctx;
+            base64_encode_init(&ctx);
+            size_t blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(token), output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
+            blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(token)+blen);
+        }
     }
-cleanup:
+
     gss_delete_sec_context(&minor_status, &gss_context, NULL);
     gss_release_buffer(&minor_status, &service);
     gss_release_buffer(&minor_status, &input_token);
Index: squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc
===================================================================
--- squid-3.5.21.orig/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc
+++ squid-3.5.21/helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc
@@ -235,10 +235,17 @@ getdomaingids(char *ad_groups, uint32_t
                           LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                 }
             }
-            if (!pstrcat(ad_groups,base64_encode_bin(ag, (int)(length+4)))) {
+            struct base64_encode_ctx ctx;
+            base64_encode_init(&ctx);
+            uint8_t *b64buf = (uint8_t *)xcalloc(base64_encode_len(length+4)*sizeof(uint8_t),1);
+            size_t blen = base64_encode_update(&ctx, b64buf, length+4, reinterpret_cast<uint8_t*>(ag));
+            blen += base64_encode_final(&ctx, b64buf+blen);
+            b64buf[sizeof(*b64buf)-1] = '\0';
+            if (!pstrcat(ad_groups, reinterpret_cast<char*>(b64buf))) {
                 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                       LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
             }
+            xfree(b64buf);
             xfree(ag);
         }
 
@@ -308,10 +315,18 @@ getextrasids(char *ad_groups, uint32_t E
                               LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                     }
                 }
-                if (!pstrcat(ad_groups,base64_encode_bin(ag, (int)length))) {
+
+                struct base64_encode_ctx ctx;
+                base64_encode_init(&ctx);
+                uint8_t *b64buf = (uint8_t *)xcalloc(base64_encode_len(length)*sizeof(uint8_t),1);
+                size_t blen = base64_encode_update(&ctx, b64buf, length, reinterpret_cast<uint8_t*>(ag));
+                blen += base64_encode_final(&ctx, b64buf+blen);
+                b64buf[sizeof(*b64buf)-1] = '\0';
+                if (!pstrcat(ad_groups, reinterpret_cast<char*>(b64buf))) {
                     debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                           LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                 }
+                xfree(b64buf);
                 xfree(ag);
 
                 rev = get1byt();
Index: squid-3.5.21/helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
===================================================================
--- squid-3.5.21.orig/helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
+++ squid-3.5.21/helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
@@ -103,7 +103,7 @@ main(int argc, char *const argv[])
     int length;
     int nstart = 0, kstart = 0;
     int nend = 0, kend = 0;
-    char *token;
+    uint8_t *token;
     char **nargs, **kargs;
     int fpid;
     FILE *FDKIN,*FDKOUT;
@@ -329,17 +329,28 @@ main(int argc, char *const argv[])
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        length = base64_decode_len(buf+3);
+        length = BASE64_DECODE_LENGTH(strlen(buf+3));;
         if (debug)
             fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
                     LogTime(), PROGRAM, buf + 3, (int) length);
 
-        if ((token = (char *)xmalloc(length)) == NULL) {
+	if ((token = static_cast<uint8_t *>(xmalloc(length))) == NULL) {
             fprintf(stderr, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM);
             return 1;
         }
 
-        length = base64_decode(token, length, buf+3);
+        struct base64_decode_ctx ctx;
+        base64_decode_init(&ctx);
+        unsigned int dstLen = 0;
+        if (!base64_decode_update(&ctx, &dstLen, token, strlen(buf+3), reinterpret_cast<const uint8_t*>(buf+3)) ||
+                !base64_decode_final(&ctx)) {
+            if (debug)
+                fprintf(stderr, "%s| %s: Invalid base64 token [%s]\n", LogTime(), PROGRAM, buf+3);
+            fprintf(stdout, "BH Invalid negotiate request token\n");
+            continue;
+        }
+        length = dstLen;
+        token[dstLen] = '\0';
 
         if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
                 (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {
@@ -375,7 +386,7 @@ main(int argc, char *const argv[])
                 strcpy(buff,tbuff);
             }
         } else {
-            free(token);
+            xfree(token);
             if (debug)
                 fprintf(stderr, "%s| %s: received Kerberos token\n",
                         LogTime(), PROGRAM);
Index: squid-3.5.21/helpers/ntlm_auth/fake/ntlm_fake_auth.cc
===================================================================
--- squid-3.5.21.orig/helpers/ntlm_auth/fake/ntlm_fake_auth.cc
+++ squid-3.5.21/helpers/ntlm_auth/fake/ntlm_fake_auth.cc
@@ -125,14 +125,13 @@ main(int argc, char *argv[])
 {
     char buf[HELPER_INPUT_BUFFER];
     int buflen = 0;
-    char decodedBuf[HELPER_INPUT_BUFFER];
+    uint8_t decodedBuf[HELPER_INPUT_BUFFER];
     int decodedLen;
     char user[NTLM_MAX_FIELD_LENGTH], domain[NTLM_MAX_FIELD_LENGTH];
     char *p;
     ntlmhdr *packet = NULL;
     char helper_command[3];
     int len;
-    char *data = NULL;
 
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
@@ -150,8 +149,13 @@ main(int argc, char *argv[])
         if ((p = strchr(buf, '\n')) != NULL)
             *p = '\0';      /* strip \n */
         buflen = strlen(buf);   /* keep this so we only scan the buffer for \0 once per loop */
-        if (buflen > 3) {
-            decodedLen = base64_decode(decodedBuf, sizeof(decodedBuf), buf+3);
+        struct base64_decode_ctx ctx;
+        base64_decode_init(&ctx);
+        unsigned int dstLen = 0;
+        if (buflen > 3 &&
+                base64_decode_update(&ctx, &dstLen, decodedBuf, buflen-3, reinterpret_cast<const uint8_t*>(buf+3)) &&
+                base64_decode_final(&ctx)) {
+            decodedLen = dstLen;
             packet = (ntlmhdr*)decodedBuf;
         } else {
             packet = NULL;
@@ -179,13 +183,19 @@ main(int argc, char *argv[])
             chal.context_high = htole32(0x003a<<16);
 
             len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
-            data = (char *) base64_encode_bin((char *) &chal, len);
+
+            struct base64_encode_ctx eCtx;
+            base64_encode_init(&eCtx);
+            uint8_t *data = (uint8_t*)xcalloc(base64_encode_len(len), 1);
+            unsigned int blen = base64_encode_update(&eCtx, data, len, reinterpret_cast<uint8_t*>(&chal));
+            blen += base64_encode_final(&eCtx, data+blen);
             if (NTLM_packet_debug_enabled) {
-                printf("TT %s\n", data);
+                printf("TT %.*s\n", blen, data);
                 debug("sending 'TT' to squid with data:\n");
                 hex_dump((unsigned char *)&chal, len);
             } else
-                SEND2("TT %s", data);
+                SEND2("TT %.*s", blen, data);
+            safe_free(data);
         } else if (strncmp(buf, "KK ", 3) == 0) {
             if (!packet) {
                 SEND("BH received KK with no data! user=");
Index: squid-3.5.21/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc
===================================================================
--- squid-3.5.21.orig/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc
+++ squid-3.5.21/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc
@@ -24,6 +24,7 @@
 #include "squid.h"
 #include "base64.h"
 #include "compat/debug.h"
+#include "helpers/defines.h"
 #include "ntlmauth/ntlmauth.h"
 #include "ntlmauth/support_bits.cci"
 #include "rfcnb/rfcnb.h"
@@ -189,8 +190,22 @@ make_challenge(char *domain, char *domai
                      NTLM_NEGOTIATE_USE_LM |
                      NTLM_NEGOTIATE_ASCII;
     ntlm_make_challenge(&chal, my_domain, my_domain_controller, (char *)challenge, NTLM_NONCE_LEN, flags);
-    int len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
-    return base64_encode_bin((char *)&chal, len);
+
+    size_t len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
+    // for lack of a good NTLM token size limit, allow up to what the helper input can be
+    // validations later will expect to be limited to that size.
+    static uint8_t b64buf[HELPER_INPUT_BUFFER-10]; /* 10 for other line fields, delimiters and terminator */
+    if (base64_encode_len(len) < sizeof(b64buf)-1) {
+        debug("base64 encoding of the token challenge will exceed %d bytes", (int)sizeof(b64buf));
+        return NULL;
+    }
+
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+    size_t blen = base64_encode_update(&ctx, b64buf, len, reinterpret_cast<const uint8_t *>(&chal));
+    blen += base64_encode_final(&ctx, b64buf+blen);
+    b64buf[blen] = '\0';
+    return reinterpret_cast<const char*>(b64buf);
 }
 
 /* returns NULL on failure, or a pointer to
@@ -500,10 +515,19 @@ manage_request()
 
     if (memcmp(buf, "KK ", 3) == 0) {   /* authenticate-request */
         /* figure out what we got */
-        int decodedLen = base64_decode(decoded, sizeof(decoded), buf+3);
+        struct base64_decode_ctx ctx;
+        base64_decode_init(&ctx);
+        unsigned int dstLen = 0;
+        int decodedLen = 0;
+        if (!base64_decode_update(&ctx, &dstLen, reinterpret_cast<uint8_t*>(decoded), strlen(buf)-3, reinterpret_cast<const uint8_t*>(buf+3)) ||
+                !base64_decode_final(&ctx)) {
+            SEND("NA Packet format error, couldn't base64-decode");
+            return;
+        }
+        decodedLen = dstLen;
 
         if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
-            SEND("NA Packet format error, couldn't base64-decode");
+            SEND("NA Packet format error, truncated packet header.");
             return;
         }
         /* fast-track-decode request type. */
Index: squid-3.5.21/lib/base64.c
===================================================================
--- squid-3.5.21.orig/lib/base64.c
+++ squid-3.5.21/lib/base64.c
@@ -13,6 +13,12 @@
 #include "squid.h"
 #include "base64.h"
 
+#if !HAVE_NETTLE_BASE64_H
+#error missing libnettle
+#endif
+
+#if 0
+
 #if HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -212,4 +218,5 @@ base64_encode(char *result, int result_s
     }
     return (out_cnt >= result_size?result_size:out_cnt);
 }
+#endif
 
Index: squid-3.5.21/src/HttpHeader.cc
===================================================================
--- squid-3.5.21.orig/src/HttpHeader.cc
+++ squid-3.5.21/src/HttpHeader.cc
@@ -1533,7 +1533,13 @@ HttpHeader::getAuth(http_hdr_type id, co
         return NULL;
 
     static char decodedAuthToken[8192];
-    const int decodedLen = base64_decode(decodedAuthToken, sizeof(decodedAuthToken)-1, field);
+    struct base64_decode_ctx ctx;
+    base64_decode_init(&ctx);
+    unsigned int decodedLen = 0;
+    if (!base64_decode_update(&ctx, &decodedLen, reinterpret_cast<uint8_t*>(decodedAuthToken), strlen(field), reinterpret_cast<const uint8_t*>(field)) ||
+            !base64_decode_final(&ctx)) {
+        return NULL;
+    }
     decodedAuthToken[decodedLen] = '\0';
     return decodedAuthToken;
 }
Index: squid-3.5.21/src/adaptation/icap/ModXact.cc
===================================================================
--- squid-3.5.21.orig/src/adaptation/icap/ModXact.cc
+++ squid-3.5.21/src/adaptation/icap/ModXact.cc
@@ -1360,11 +1360,14 @@ void Adaptation::Icap::ModXact::makeRequ
         String vh=virgin.header->header.getByName("Proxy-Authorization");
         buf.Printf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(vh));
     } else if (request->extacl_user.size() > 0 && request->extacl_passwd.size() > 0) {
-        char loginbuf[256];
-        snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
-                 SQUIDSTRINGPRINT(request->extacl_user),
-                 SQUIDSTRINGPRINT(request->extacl_passwd));
-        buf.Printf("Proxy-Authorization: Basic %s\r\n", old_base64_encode(loginbuf));
+        struct base64_encode_ctx ctx;
+        base64_encode_init(&ctx);
+        uint8_t base64buf[base64_encode_len(MAX_LOGIN_SZ)];
+        size_t resultLen = base64_encode_update(&ctx, base64buf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
+        resultLen += base64_encode_update(&ctx, base64buf+resultLen, 1, reinterpret_cast<const uint8_t*>(":"));
+        resultLen += base64_encode_update(&ctx, base64buf+resultLen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
+        resultLen += base64_encode_final(&ctx, base64buf+resultLen);
+        buf.Printf("Proxy-Authorization: Basic %.*s\r\n", resultLen, base64buf);
     }
 
     // share the cross-transactional database records if needed
@@ -1510,16 +1513,25 @@ void Adaptation::Icap::ModXact::makeAllo
 void Adaptation::Icap::ModXact::makeUsernameHeader(const HttpRequest *request, MemBuf &buf)
 {
 #if USE_AUTH
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+
+    const char *value = NULL;
     if (request->auth_user_request != NULL) {
-        char const *name = request->auth_user_request->username();
-        if (name) {
-            const char *value = TheConfig.client_username_encode ? old_base64_encode(name) : name;
-            buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
-        }
+        value = request->auth_user_request->username();
     } else if (request->extacl_user.size() > 0) {
-        const char *value = TheConfig.client_username_encode ? old_base64_encode(request->extacl_user.termedBuf()) : request->extacl_user.termedBuf();
-        buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
+        value = request->extacl_user.termedBuf();
     }
+
+    if (value) {
+        if (TheConfig.client_username_encode) {
+            uint8_t base64buf[base64_encode_len(MAX_LOGIN_SZ)];
+            size_t resultLen = base64_encode_update(&ctx, base64buf, strlen(value), reinterpret_cast<const uint8_t*>(value));
+            resultLen += base64_encode_final(&ctx, base64buf+resultLen);
+            buf.Printf("%s: %.*s\r\n", TheConfig.client_username_header, resultLen, base64buf);
+        } else
+            buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
+     }
 #endif
 }
 
Index: squid-3.5.21/src/auth/digest/Config.cc
===================================================================
--- squid-3.5.21.orig/src/auth/digest/Config.cc
+++ squid-3.5.21/src/auth/digest/Config.cc
@@ -99,7 +99,11 @@ authDigestNonceEncode(digest_nonce_h * n
     if (nonce->key)
         xfree(nonce->key);
 
-    nonce->key = xstrdup(base64_encode_bin((char *) &(nonce->noncedata), sizeof(digest_nonce_data)));
+    nonce->key = xcalloc(base64_encode_len(sizeof(digest_nonce_data)), 1);
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+    size_t blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(nonce->key), sizeof(digest_nonce_data), reinterpret_cast<const uint8_t*>(&(nonce->noncedata)));
+    blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(nonce->key)+blen);
 }
 
 digest_nonce_h *
Index: squid-3.5.21/src/http.cc
===================================================================
--- squid-3.5.21.orig/src/http.cc
+++ squid-3.5.21/src/http.cc
@@ -1606,9 +1606,13 @@ httpFixupAuthentication(HttpRequest * re
         }
     }
 
+    uint8_t loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
+    int blen;
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+
     /* Special mode to pass the username to the upstream cache */
     if (*request->peer_login == '*') {
-        char loginbuf[256];
         const char *username = "-";
 
         if (request->extacl_user.size())
@@ -1617,11 +1621,10 @@ httpFixupAuthentication(HttpRequest * re
         else if (request->auth_user_request != NULL)
             username = request->auth_user_request->username();
 #endif
-
-        snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, request->peer_login + 1);
-
-        httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          old_base64_encode(loginbuf));
+	blen = base64_encode_update(&ctx, loginbuf, strlen(username), reinterpret_cast<const uint8_t*>(username));
+        blen += base64_encode_update(&ctx, loginbuf+blen, strlen(request->peer_login +1), reinterpret_cast<const uint8_t*>(request->peer_login +1));
+        blen += base64_encode_final(&ctx, loginbuf+blen);
+        httpHeaderPutStrf(hdr_out, header, "Basic %.*s", blen, loginbuf);
         return;
     }
 
@@ -1629,12 +1632,12 @@ httpFixupAuthentication(HttpRequest * re
     if (request->extacl_user.size() && request->extacl_passwd.size() &&
             (strcmp(request->peer_login, "PASS") == 0 ||
              strcmp(request->peer_login, "PROXYPASS") == 0)) {
-        char loginbuf[256];
-        snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH,
-                 SQUIDSTRINGPRINT(request->extacl_user),
-                 SQUIDSTRINGPRINT(request->extacl_passwd));
-        httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                          old_base64_encode(loginbuf));
+
+	blen = base64_encode_update(&ctx, loginbuf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
+        blen += base64_encode_update(&ctx, loginbuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
+        blen += base64_encode_update(&ctx, loginbuf+blen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
+        blen += base64_encode_final(&ctx, loginbuf+blen);
+        httpHeaderPutStrf(hdr_out, header, "Basic %.*s", blen, loginbuf);
         return;
     }
     // if no external user credentials are available to fake authentication with PASS acts like PASSTHRU
@@ -1657,8 +1660,9 @@ httpFixupAuthentication(HttpRequest * re
     }
 #endif /* HAVE_KRB5 && HAVE_GSSAPI */
 
-    httpHeaderPutStrf(hdr_out, header, "Basic %s",
-                      old_base64_encode(request->peer_login));
+    blen = base64_encode_update(&ctx, loginbuf, strlen(request->peer_login), reinterpret_cast<const uint8_t*>(request->peer_login));
+    blen += base64_encode_final(&ctx, loginbuf+blen);
+    httpHeaderPutStrf(hdr_out, header, "Basic %.*s", blen, loginbuf);
     return;
 }
 
@@ -1795,8 +1799,14 @@ HttpStateData::httpBuildRequestHeader(Ht
     /* append Authorization if known in URL, not in header and going direct */
     if (!hdr_out->has(HDR_AUTHORIZATION)) {
         if (!request->flags.proxying && request->login[0] != '\0') {
-            httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
-                              old_base64_encode(request->login));
+            static uint8_t result[base64_encode_len(MAX_URL*2)]; // should be big enough for a single URI segment
+            struct base64_encode_ctx ctx;
+            base64_encode_init(&ctx);
+            unsigned int blen = base64_encode_update(&ctx, result, strlen(request->login), (const uint8_t*)request->login);
+            blen += base64_encode_final(&ctx, result+blen);
+            result[blen] = '\0';
+            if (blen)
+                httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %.*s", blen, result);
         }
     }
 
Index: squid-3.5.21/src/peer_proxy_negotiate_auth.cc
===================================================================
--- squid-3.5.21.orig/src/peer_proxy_negotiate_auth.cc
+++ squid-3.5.21/src/peer_proxy_negotiate_auth.cc
@@ -557,10 +557,14 @@ char *peer_proxy_negotiate_auth(char *pr
 
     debugs(11, 5, HERE << "Got token with length " << output_token.length);
     if (output_token.length) {
+        static uint8_t b64buf[8192]; // XXX: 8KB only because base64_encode_bin() used to.
+        struct base64_encode_ctx ctx;
+        base64_encode_init(&ctx);
+        size_t blen = base64_encode_update(&ctx, b64buf, output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
+        blen += base64_encode_final(&ctx, b64buf+blen);
+        b64buf[blen] = '\0';
 
-        token =
-            (char *) base64_encode_bin((const char *) output_token.value,
-                                       output_token.length);
+        token = reinterpret_cast<char*>(b64buf);
     }
 
 cleanup:
Index: squid-3.5.21/tools/cachemgr.cc
===================================================================
--- squid-3.5.21.orig/tools/cachemgr.cc
+++ squid-3.5.21/tools/cachemgr.cc
@@ -1079,7 +1079,11 @@ make_pub_auth(cachemgr_request * req)
 
     const int encodedLen = base64_encode_len(bufLen);
     req->pub_auth = (char *) xmalloc(encodedLen);
-    base64_encode_str(req->pub_auth, encodedLen, buf, bufLen);
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+    size_t blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth), bufLen, reinterpret_cast<uint8_t*>(buf));
+    blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth)+blen);
+    req->pub_auth[blen] = '\0';
     debug("cmgr: encoded: '%s'\n", req->pub_auth);
 }
 
@@ -1098,9 +1102,16 @@ decode_pub_auth(cachemgr_request * req)
     if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
         return;
 
-    const int decodedLen = base64_decode_len(req->pub_auth);
+    unsigned int decodedLen = BASE64_DECODE_LENGTH(strlen(req->pub_auth));
     buf = (char*)xmalloc(decodedLen);
-    base64_decode(buf, decodedLen, req->pub_auth);
+    struct base64_decode_ctx ctx;
+    base64_decode_init(&ctx);
+    base64_decode_update(&ctx, &decodedLen, reinterpret_cast<uint8_t*>(buf), strlen(req->pub_auth), reinterpret_cast<const uint8_t*>(req->pub_auth));
+    if (!base64_decode_final(&ctx)) {
+        debug("cmgr: base64 decode failure. Incomplete auth token string.\n");
+        xfree(buf);
+        return;
+    }
 
     debug("cmgr: length ok\n");
 
@@ -1180,14 +1191,18 @@ make_auth_header(const cachemgr_request
     if (encodedLen <= 0)
         return "";
 
-    char *str64 = static_cast<char*>(xmalloc(encodedLen));
-    base64_encode_str(str64, encodedLen, buf, bufLen);
+    uint8_t *str64 = static_cast<uint8_t*>(xmalloc(encodedLen));
+    struct base64_encode_ctx ctx;
+    base64_encode_init(&ctx);
+    size_t blen = base64_encode_update(&ctx, str64, bufLen, reinterpret_cast<uint8_t*>(buf));
+    blen += base64_encode_final(&ctx, str64+blen);
+    str64[blen] = '\0';
 
-    stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
+    stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %.*s\r\n", blen, str64);
 
     assert(stringLength < sizeof(buf));
 
-    snprintf(&buf[stringLength], sizeof(buf) - stringLength, "Proxy-Authorization: Basic %s\r\n", str64);
+    snprintf(&buf[stringLength], sizeof(buf) - stringLength, "Proxy-Authorization: Basic %.*s\r\n", blen, str64);
 
     xfree(str64);
     return buf;
Index: squid-3.5.21/tools/squidclient/gssapi_support.cc
===================================================================
--- squid-3.5.21.orig/tools/squidclient/gssapi_support.cc
+++ squid-3.5.21/tools/squidclient/gssapi_support.cc
@@ -102,7 +102,10 @@ GSSAPI_token(const char *server)
 
     if (!server) {
         std::cerr << "ERROR: GSSAPI: No server name" << std::endl;
-        return (char *)"ERROR";
+	token = new char[6];
+	memcpy(token, "ERROR", 5);
+        token[5] = '\0';
+        return token;
     }
     service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
     snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
@@ -127,15 +130,24 @@ GSSAPI_token(const char *server)
                                             NULL,
                                             NULL);
 
-        if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()")) {
+        if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()") && output_token.length) {
+            uint8_t *b64buf = new uint8_t[base64_encode_len(output_token.length)];
+            struct base64_encode_ctx ctx;
+            base64_encode_init(&ctx);
+            size_t blen = base64_encode_update(&ctx, b64buf, output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
+            blen += base64_encode_final(&ctx, b64buf+blen);
+            b64buf[blen] = '\0';
 
-            if (output_token.length)
-                token = (char *) base64_encode_bin((const char *) output_token.value, output_token.length);
+	    token = reinterpret_cast<char*>(b64buf);
         }
     }
 
-    if (!output_token.length)
-        token = (char *) "ERROR";
+    if (!output_token.length) {
+        token = new char[6];
+        memcpy(token, "ERROR", 5);
+        token[5] = '\0';
+    }
+
     gss_delete_sec_context(&minor_status, &gss_context, NULL);
     gss_release_buffer(&minor_status, &service);
     gss_release_buffer(&minor_status, &input_token);
Index: squid-3.5.21/tools/squidclient/squidclient.cc
===================================================================
--- squid-3.5.21.orig/tools/squidclient/squidclient.cc
+++ squid-3.5.21/tools/squidclient/squidclient.cc
@@ -417,6 +417,9 @@ main(int argc, char *argv[])
             snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards);
             strcat(msg, buf);
         }
+        struct base64_encode_ctx ctx;
+        base64_encode_init(&ctx);
+        size_t blen;
         if (proxy_user) {
             const char *user = proxy_user;
             const char *password = proxy_password;
@@ -428,8 +431,11 @@ main(int argc, char *argv[])
                 std::cerr << "ERROR: Proxy password missing" << std::endl;
                 exit(1);
             }
-            snprintf(buf, BUFSIZ, "%s:%s", user, password);
-            snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", old_base64_encode(buf));
+            blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf), strlen(user), reinterpret_cast<const uint8_t*>(user));
+            blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), 1, reinterpret_cast<const uint8_t*>(":"));
+            blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), strlen(password), reinterpret_cast<const uint8_t*>(password));
+            blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(buf+blen));
+            snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %.*s\r\n", blen, buf);
             strcat(msg, buf);
         }
         if (www_user) {
@@ -443,22 +449,29 @@ main(int argc, char *argv[])
                 std::cerr << "ERROR: WWW password missing" << std::endl;
                 exit(1);
             }
-            snprintf(buf, BUFSIZ, "%s:%s", user, password);
-            snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", old_base64_encode(buf));
+            blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf), strlen(user), reinterpret_cast<const uint8_t*>(user));
+            blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), 1, reinterpret_cast<const uint8_t*>(":"));
+            blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), strlen(password), reinterpret_cast<const uint8_t*>(password));
+            blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(buf+blen));
+            snprintf(buf, BUFSIZ, "Authorization: Basic %.*s\r\n", blen, buf);
             strcat(msg, buf);
         }
 #if HAVE_GSSAPI
         if (www_neg) {
             if (host) {
-                snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", GSSAPI_token(host));
+                const char *token = GSSAPI_token(host);
+                snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", token);
                 strcat(msg, buf);
+                delete token;
             } else
                 std::cerr << "ERROR: server host missing" << std::endl;
         }
         if (proxy_neg) {
             if (Transport::Config.hostname) {
-                snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", GSSAPI_token(Transport::Config.hostname));
+                const char *token = GSSAPI_token(Transport::Config.hostname);
+                snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", token);
                 strcat(msg, buf);
+                delete token;
             } else
                 std::cerr << "ERROR: proxy server host missing" << std::endl;
         }
