[squid-dev] [PATCH] Base64 crypto replacement

Amos Jeffries squid3 at treenet.co.nz
Thu Dec 18 11:20:32 UTC 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The existing Squid base64 code has ambiguous copyright licensing. In
particular it only references 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 legally certain.

It has also been heavily modified and customized over the decades
since importing.

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.

Amos
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)

iQEcBAEBAgAGBQJUkrh/AAoJELJo5wb/XPRjCT8H/i79ig1iVDDgRU/oAeEWcWJL
buAiVWNVOJI44gZlCXUzmhF/jsp1iHhif4X7ep3qNDvOW18iglkZiSCgS0FlGiSh
6glAUOCHTB7PXBuf6fQOtHWrE3zvxnTCM7lNJkZSPU8clM2rAArGh4uGTo4J6cez
Z8D4ESVJ5GzF13Z7UnwdLauQClU8Bd2x28ujoBGa3fZEihjnU59YMj+AfcJNEYm6
hE3G/vj/n2CoAGFHQFqso4juRDSWaoJHJZRYVxrB41jkc5nJkD/ewudreg7o8K3i
vBIAWNipLD1CwcdqxqGZjVsnDDYrvEPzC5VwEqEkzksCCAyI6u1bFCPqJOQhZHE=
=fzy9
-----END PGP SIGNATURE-----
-------------- next part --------------
=== modified file 'CREDITS'
--- CREDITS	2014-12-06 13:43:32 +0000
+++ CREDITS	2014-12-17 19:24:23 +0000
@@ -1465,40 +1465,75 @@
  *                       All Rights Reserved
  *
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted,
  * provided that the above copyright notice appear in all copies and that
  * both that copyright notice and this permission notice appear in
  * supporting documentation, and that the name of CMU not be
  * used in advertising or publicity pertaining to distribution of the
  * software without specific, written prior permission.
  *
  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
 
 ==============================================================================
 
+include/base64.h:
+lib/base64.c:
+
+/*
+   Copyright (C) 2002 Niels Möller, Dan Egnor
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+==============================================================================
+
 include/heap.h,
 lib/heap.cc:
 
  * AUTHOR: John Dilley, Hewlett Packard
 
  * Copyright (C) 1999 by Hewlett Packard
 
 ==============================================================================
 
 include/md5.h,
 lib/md5.c:
 
  * The algorithm is due to Ron Rivest.  This code was
  * written by Colin Plumb in 1993, no copyright is claimed.
  * This code is in the public domain; do with it what you wish.
 
 ==============================================================================
 
 include/parse.h,
 include/snmp_api.h,

=== modified file 'configure.ac'
--- configure.ac	2014-12-16 12:23:58 +0000
+++ configure.ac	2014-12-16 14:44:28 +0000
@@ -1182,41 +1182,41 @@
 
 # Cryptograhic libraries
 AC_ARG_WITH(nettle,
   AS_HELP_STRING([--without-nettle],[Compile without the Nettle crypto library.]),[
 case "$with_nettle" in
   yes|no)
     : # Nothing special to do here
     ;;
   *)
     if test ! -d "$withval" ; then
       AC_MSG_ERROR([--with-nettle path does not point to a directory])
     fi
     NETTLELIBDIR="-L$with_nettle/lib"
     CPPFLAGS="-I$with_nettle/include $CPPFLAGS"
     with_nettle=yes
   esac
 ])
 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}])
 AC_SUBST(NETTLELIB)
 
 dnl Check for libcrypt
 CRYPTLIB=
 dnl Some of our helpers use crypt(3) which may be in libc, or in
 dnl libcrypt (eg FreeBSD)
 AC_CHECK_LIB(crypt, crypt, [CRYPTLIB="-lcrypt"])
 dnl Solaris10 provides MD5 natively through libmd5
 AC_CHECK_LIB(md5, MD5Init, [CRYPTLIB="$CRYPTLIB -lmd5"])
 AC_SUBST(CRYPTLIB)
 
 SSLLIB=""
 
 dnl User may want to disable GnuTLS
 AC_ARG_WITH(gnutls,
   AS_HELP_STRING([--without-gnutls],
                  [Do not use GnuTLS for SSL. Default: auto-detect]), [ 

=== modified file 'helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc'
--- helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc	2014-10-29 04:26:36 +0000
+++ helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc	2014-12-18 11:01:08 +0000
@@ -295,46 +295,56 @@
             }
             xfree(token);
             fprintf(stdout, "BH quit command\n");
             exit(0);
         }
         if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
             debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
             fprintf(stdout, "BH Invalid request\n");
             continue;
         }
         if (!strncmp(buf, "YR", 2)) {
             if (gss_context != GSS_C_NO_CONTEXT)
                 gss_delete_sec_context(&minor_status, &gss_context, NULL);
             gss_context = GSS_C_NO_CONTEXT;
         }
         if (strlen(buf) <= 3) {
             debug((char *) "%s| %s: ERROR: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf);
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        input_token.length = (size_t)base64_decode_len(buf+3);
+        const uint8_t *b64Token = reinterpret_cast<const uint8_t*>(buf+3);
+        input_token.length = BASE64_DECODE_LENGTH(strlen(buf+3));
         debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
-              LogTime(), PROGRAM, buf + 3, (int) input_token.length);
+              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);
+        size_t dstLen = 0;
+        if (!base64_decode_update(&ctx, &dstLen, static_cast<uint8_t*>(input_token.value), input_token.length, 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))) {
             debug((char *) "%s| %s: WARNING: received type %d NTLM token\n",
                   LogTime(), PROGRAM,
                   (int) *((unsigned char *) input_token.value +
                           sizeof ntlmProtocol));
             fprintf(stdout, "BH received type %d NTLM token\n",
                     (int) *((unsigned char *) input_token.value +
                             sizeof ntlmProtocol));
             goto cleanup;
         }
         if (service_principal) {
             if (strcasecmp(service_principal, "GSS_C_NO_NAME")) {
                 major_status = gss_import_name(&minor_status, &service,
                                                (gss_OID) GSS_C_NULL_OID, &server_name);
 
             } else {
                 server_name = GSS_C_NO_NAME;
                 major_status = GSS_S_COMPLETE;
@@ -347,48 +357,51 @@
 
         if (check_gss_err(major_status, minor_status, "gss_import_name()", log, 1))
             goto cleanup;
 
         major_status =
             gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
                              GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
         if (check_gss_err(major_status, minor_status, "gss_acquire_cred()", log, 1))
             goto cleanup;
 
         major_status = gss_accept_sec_context(&minor_status,
                                               &gss_context,
                                               server_creds,
                                               &input_token,
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               &client_name, NULL, &output_token, &ret_flags, NULL, NULL);
 
         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;
             if (major_status & GSS_S_CONTINUE_NEEDED) {
                 debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
                 fprintf(stdout, "TT %s\n", token);
                 goto cleanup;
             }
             gss_release_buffer(&minor_status, &output_token);
             major_status =
                 gss_display_name(&minor_status, client_name, &output_token,
                                  NULL);
 
             if (check_gss_err(major_status, minor_status, "gss_display_name()", log, 1))
                 goto cleanup;
             user = (char *) xmalloc(output_token.length + 1);
             if (user == NULL) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;

=== modified file 'helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc'
--- helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc	2014-09-13 13:31:49 +0000
+++ helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc	2014-12-17 17:22:59 +0000
@@ -169,60 +169,59 @@
     gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
     char *token = NULL;
 
     setbuf(stdout, NULL);
     setbuf(stdin, NULL);
 
     if (!proxy) {
         fprintf(stderr, "%s| %s: Error: No proxy server name\n", LogTime(),
                 PROGRAM);
         return NULL;
     }
     service.value = xmalloc(strlen("HTTP") + strlen(proxy) + 2);
     snprintf((char *) service.value, strlen("HTTP") + strlen(proxy) + 2, "%s@%s", "HTTP", proxy);
     service.length = strlen((char *) service.value);
 
     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);
-
-    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);
+        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()") && 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);
     gss_release_buffer(&minor_status, &output_token);
     gss_release_name(&minor_status, &server_name);
 
     return token;
 }
 
 int
 main(int argc, char *argv[])
 {
     const char *Token;
     int count;
 
     if (argc < 2) {
         fprintf(stderr, "%s| %s: Error: No proxy server name given\n",
                 LogTime(), PROGRAM);
         return 99;
     }

=== modified file 'helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc'
--- helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc	2014-10-29 04:26:36 +0000
+++ helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc	2014-12-12 12:37:17 +0000
@@ -232,44 +232,51 @@
         /* prepend rids with DomainID */
         length=1+1+6+nauth*4;
         for (l=0; l<(int)GroupCount; l++) {
             ag=(char *)xcalloc((length+4)*sizeof(char),1);
             memcpy((void *)ag,(const void*)&p[bpos],1);
             memcpy((void *)&ag[1],(const void*)&p[bpos+1],1);
             ag[1] = ag[1]+1;
             memcpy((void *)&ag[2],(const void*)&p[bpos+2],6+nauth*4);
             memcpy((void *)&ag[length],(const void*)Rids[l],4);
             if (l==0) {
                 if (!xstrcpy(ad_groups,"group=")) {
                     debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                           LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                 }
             } else {
                 if (!xstrcat(ad_groups," group=")) {
                     debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                           LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                 }
             }
-            if (!xstrcat(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 (!xstrcat(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);
         }
 
         /* mainly for debug only */
         rev = get1byt();
         bpos = bpos + 1; /*nsub*/
         idauth = get6byt_be();
 
         snprintf(dli,sizeof(dli),"S-%d-%lu",rev,(long unsigned int)idauth);
         for ( l=0; l<(int)nauth; l++ ) {
             sauth = get4byt();
             snprintf((char *)&dli[strlen(dli)],sizeof(dli)-strlen(dli),"-%u",sauth);
         }
         debug((char *) "%s| %s: INFO: Got DomainLogonId %s\n", LogTime(), PROGRAM, dli);
     }
     return ad_groups;
 }
 
 char *
 getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount)
@@ -304,44 +311,51 @@
             uint32_t sauth;
             int k;
 
             if (pa[l] != 0) {
                 nauth = get4byt();
 
                 length = 1+1+6+nauth*4;
                 ag = (char *)xcalloc((length)*sizeof(char),1);
                 memcpy((void *)ag,(const void*)&p[bpos],length);
                 if (!ad_groups) {
                     if (!xstrcpy(ad_groups,"group=")) {
                         debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                               LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                     }
                 } else {
                     if (!xstrcat(ad_groups," group=")) {
                         debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
                               LogTime(), PROGRAM, MAX_PAC_GROUP_SIZE, ad_groups);
                     }
                 }
-                if (!xstrcat(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 (!xstrcat(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();
                 bpos = bpos + 1; /* nsub */
                 idauth = get6byt_be();
 
                 snprintf(es,sizeof(es),"S-%d-%lu",rev,(long unsigned int)idauth);
                 for ( k=0; k<(int)nauth; k++ ) {
                     sauth = get4byt();
                     snprintf((char *)&es[strlen(es)],sizeof(es)-strlen(es),"-%u",sauth);
                 }
                 debug((char *) "%s| %s: INFO: Got ExtraSid %s\n", LogTime(), PROGRAM, es);
             }
         }
         xfree(pa);
     }
     return ad_groups;
 }
 
 char *

=== modified file 'helpers/negotiate_auth/wrapper/negotiate_wrapper.cc'
--- helpers/negotiate_auth/wrapper/negotiate_wrapper.cc	2014-09-13 13:31:49 +0000
+++ helpers/negotiate_auth/wrapper/negotiate_wrapper.cc	2014-12-18 10:58:01 +0000
@@ -86,41 +86,41 @@
 {
     fprintf(stderr, "Usage: \n");
     fprintf(stderr, "negotiate_wrapper [-h] [-d] --ntlm ntlm helper + arguments --kerberos kerberos helper + arguments\n");
     fprintf(stderr, "-h help\n");
     fprintf(stderr, "-d full debug\n");
     fprintf(stderr, "--ntlm full ntlm helper path with arguments\n");
     fprintf(stderr, "--kerberos full kerberos helper path with arguments\n");
 }
 
 int
 main(int argc, char *const argv[])
 {
     char buf[MAX_AUTHTOKEN_LEN];
     char tbuff[MAX_AUTHTOKEN_LEN];
     char buff[MAX_AUTHTOKEN_LEN+2];
     char *c;
     int debug = 0;
     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;
     FILE *FDNIN,*FDNOUT;
     int pkin[2];
     int pkout[2];
     int pnin[2];
     int pnout[2];
 
     setbuf(stdout, NULL);
     setbuf(stdin, NULL);
 
     if (argc ==1 || !strncasecmp(argv[1],"-h",2)) {
         usage();
         return 0;
     }
 
     int j = 1;
     if (!strncasecmp(argv[1],"-d",2)) {
         debug = 1;
@@ -312,87 +312,98 @@
             continue;
         }
         if (!strncmp(buf, "QQ", 2)) {
             fprintf(stdout, "BH quit command\n");
             return 0;
         }
         if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
             if (debug)
                 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
                         PROGRAM, buf);
             fprintf(stdout, "BH Invalid request\n");
             continue;
         }
         if (strlen(buf) <= 3) {
             if (debug)
                 fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
                         LogTime(), PROGRAM, buf);
             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);
+        size_t 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))) {
             free(token);
             if (debug)
                 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
                         LogTime(), PROGRAM, (int) *((unsigned char *) token +
                                                     sizeof ntlmProtocol));
             fprintf(FDNIN, "%s\n",buf);
             if (fgets(tbuff, sizeof(tbuff) - 1, FDNOUT) == NULL) {
                 if (ferror(FDNOUT)) {
                     fprintf(stderr,
                             "fgets() failed! dying..... errno=%d (%s)\n",
                             ferror(FDNOUT), strerror(ferror(FDNOUT)));
                     return 1;
                 }
                 fprintf(stderr, "%s| %s: Error reading NTLM helper response\n",
                         LogTime(), PROGRAM);
                 return 0;
             }
             /*
                    Need to translate NTLM reply to Negotiate reply
                    AF user => AF blob user
                NA reason => NA blob reason
                Set blob to '='
                 */
             if (strlen(tbuff) >= 3 && (!strncmp(tbuff,"AF ",3) || !strncmp(tbuff,"NA ",3))) {
                 strncpy(buff,tbuff,3);
                 buff[3]='=';
                 for (unsigned int i=2; i<=strlen(tbuff); ++i)
                     buff[i+2] = tbuff[i];
             } else {
                 strcpy(buff,tbuff);
             }
         } else {
-            free(token);
+            xfree(token);
             if (debug)
                 fprintf(stderr, "%s| %s: received Kerberos token\n",
                         LogTime(), PROGRAM);
 
             fprintf(FDKIN, "%s\n",buf);
             if (fgets(buff, sizeof(buff) - 1, FDKOUT) == NULL) {
                 if (ferror(FDKOUT)) {
                     fprintf(stderr,
                             "fgets() failed! dying..... errno=%d (%s)\n",
                             ferror(FDKOUT), strerror(ferror(FDKOUT)));
                     return 1;
                 }
                 fprintf(stderr, "%s| %s: Error reading Kerberos helper response\n",
                         LogTime(), PROGRAM);
                 return 0;
             }
         }
         fprintf(stdout,"%s",buff);
         if (debug)
             fprintf(stderr, "%s| %s: Return '%s'\n",

=== modified file 'helpers/ntlm_auth/fake/ntlm_fake_auth.cc'
--- helpers/ntlm_auth/fake/ntlm_fake_auth.cc	2014-09-13 13:31:49 +0000
+++ helpers/ntlm_auth/fake/ntlm_fake_auth.cc	2014-12-18 10:53:08 +0000
@@ -114,101 +114,111 @@
             usage();
             exit(0);
         case '?':
             opt = optopt;
             /* fall thru to default */
         default:
             fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
             usage();
             had_error = 1;
         }
     }
     if (had_error)
         exit(1);
 }
 
 int
 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);
 
     my_program_name = argv[0];
 
     process_options(argc, argv);
 
     debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name);
 
     while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) {
         user[0] = '\0';		/*no user code */
         domain[0] = '\0';		/*no domain code */
 
         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);
+        size_t 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;
             decodedLen = 0;
         }
+
         if (buflen > 3 && NTLM_packet_debug_enabled) {
             strncpy(helper_command, buf, 2);
             helper_command[2] = '\0';
             debug("Got '%s' from Squid with data:\n", helper_command);
             hex_dump((unsigned char *)decodedBuf, decodedLen);
         } else
             debug("Got '%s' from Squid\n", buf);
 
         if (strncmp(buf, "YR", 2) == 0) {
             char nonce[NTLM_NONCE_LEN];
             ntlm_challenge chal;
             ntlm_make_nonce(nonce);
             if (buflen > 3) {
                 ntlm_negotiate *nego = (ntlm_negotiate *)packet;
                 ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, nego->flags);
             } else {
                 ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, NTLM_NEGOTIATE_ASCII);
             }
             // TODO: find out what this context means, and why only the fake auth helper contains it.
             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);
+            size_t 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=");
             } else if (ntlm_validate_packet(packet, NTLM_AUTHENTICATE) == NTLM_ERR_NONE) {
                 if (ntlm_unpack_auth((ntlm_authenticate *)packet, user, domain, decodedLen) == NTLM_ERR_NONE) {
                     lc(user);
                     if (strip_domain_enabled) {
                         SEND2("AF %s", user);
                     } else {
                         SEND4("AF %s%s%s", domain, (*domain?"\\":""), user);
                     }
                 } else {
                     lc(user);
                     SEND4("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user);
                 }
             } else {
                 SEND("BH wrong packet type! user=");
             }
         }
     }

=== modified file 'helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc'
--- helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc	2014-09-13 13:31:49 +0000
+++ helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc	2014-12-18 10:51:18 +0000
@@ -7,40 +7,41 @@
  */
 
 /*
  * (C) 2000 Francesco Chemolli <kinkie at kame.usr.dsi.unimi.it>
  * Distributed freely under the terms of the GNU General Public License,
  * version 2. See the file COPYING for licensing details
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  */
 
 #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"
 #include "smblib/smblib.h"
 
 #include <cassert>
 #include <cctype>
 #include <cerrno>
 #include <csignal>
 #include <cstdlib>
 #include <cstring>
 #include <ctime>
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #if HAVE_GETOPT_H
 #include <getopt.h>
 #endif
 #if HAVE_UNISTD_H
 #include <unistd.h>
@@ -172,42 +173,54 @@
 make_challenge(char *domain, char *domain_controller)
 {
     /* trying to circumvent some strange problem wih pointers in SMBLib */
     /* Ugly as hell, but the lib is going to be dropped... */
     strncpy(my_domain, domain, sizeof(my_domain)-1);
     my_domain[sizeof(my_domain)-1] = '\0';
     strncpy(my_domain_controller, domain_controller, sizeof(my_domain_controller)-1);
     my_domain_controller[sizeof(my_domain_controller)-1] = '\0';
 
     if (init_challenge(my_domain, my_domain_controller) > 0) {
         return NULL;
     }
     ntlm_challenge chal;
     uint32_t flags = NTLM_REQUEST_NON_NT_SESSION_KEY |
                      NTLM_CHALLENGE_TARGET_IS_DOMAIN |
                      NTLM_NEGOTIATE_ALWAYS_SIGN |
                      NTLM_NEGOTIATE_USE_NTLM |
                      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", 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
  * the user's credentials (domain\\username)
  * upon success. WARNING. It's pointing to static storage.
  * In case of problem sets as side-effect ntlm_errno to one of the
  * codes defined in ntlm.h
  */
 char *
 ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
 {
     int rv;
     char pass[MAX_PASSWD_LEN+1];
     char *domain = credentials;
     char *user;
     lstring tmp;
 
     if (handle == NULL) {	/*if null we aren't connected, but it shouldn't happen */
         debug("Weird, we've been disconnected\n");
         ntlm_errno = NTLM_ERR_NOT_CONNECTED;
@@ -462,44 +475,53 @@
     char buf[NTLM_BLOB_BUFFER_SIZE];
     char decoded[NTLM_BLOB_BUFFER_SIZE];
     const char *ch;
     char *ch2, *cred = NULL;
 
     if (fgets(buf, NTLM_BLOB_BUFFER_SIZE, stdin) == NULL) {
         fprintf(stderr, "fgets() failed! dying..... errno=%d (%s)\n", errno,
                 strerror(errno));
         exit(1);		/* BIIG buffer */
     }
     debug("managing request\n");
     ch2 = (char*)memchr(buf, '\n', NTLM_BLOB_BUFFER_SIZE);	/* safer against overrun than strchr */
     if (ch2) {
         *ch2 = '\0';		/* terminate the string at newline. */
         ch = ch2;
     }
     debug("ntlm authenticator. Got '%s' from Squid\n", buf);
 
     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);
+        size_t 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. */
         fast_header = (ntlmhdr *) decoded;
 
         /* sanity-check: it IS a NTLMSSP packet, isn't it? */
         if (ntlm_validate_packet(fast_header, NTLM_ANY) < 0) {
             SEND("NA Broken authentication packet");
             return;
         }
         switch (le32toh(fast_header->type)) {
         case NTLM_NEGOTIATE:
             SEND("NA Invalid negotiation request received");
             return;
             /* notreached */
         case NTLM_CHALLENGE:
             SEND("NA Got a challenge. We refuse to have our authority disputed");
             return;
             /* notreached */
         case NTLM_AUTHENTICATE:

=== modified file 'include/base64.h'
--- include/base64.h	2014-09-02 01:08:58 +0000
+++ include/base64.h	2014-12-17 19:27:09 +0000
@@ -1,59 +1,95 @@
 /*
  * Copyright (C) 1996-2014 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_BASE64_H
 #define _SQUID_BASE64_H
 
+#if HAVE_NETTLE_BASE64_H
+#include <nettle/base64.h>
+
+#else /* Base64 functions copied from Nettle 3.0 under GPLv2, with adjustments */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
     // Decoding functions
 
-    /// Calculate the decoded length of a given nul-terminated encoded string.
-    /// NULL pointer and empty strings are accepted, result is zero.
-    /// Any return value <= zero means no decoded result can be produced.
-    extern int base64_decode_len(const char *encodedData);
-
-    /// Decode a base-64 encoded blob into a provided buffer.
-    /// Will not terminate the resulting string.
-    /// In-place decoding overlap is supported if result is equal or earlier that the source pointer.
-    ///
-    /// \return number of bytes filled in result.
-    extern int base64_decode(char *result, unsigned int result_max_size, const char *encoded);
+    /// Maximum length of output for base64_decode_update.
+    /// We have at most 6 buffered bits, and a total of (length + 1) * 6 bits.
+#   define BASE64_DECODE_LENGTH(length) ((((length) + 1) * 6) / 8)
+
+    struct base64_decode_ctx
+    {
+        unsigned word;   /* Leftover bits */
+        unsigned bits;   /* Number buffered bits */
+
+        /* Number of padding characters encountered */
+        unsigned padding;
+    };
+
+    void base64_decode_init(struct base64_decode_ctx *ctx);
+
+    /* Returns 1 on success, 0 on error. DST should point to an area of
+     * size at least BASE64_DECODE_LENGTH(length). The amount of data
+     * generated is returned in *DST_LENGTH.
+     */
+    int base64_decode_update(struct base64_decode_ctx *ctx,
+                     size_t *dst_length,
+                     uint8_t *dst,
+                     size_t src_length,
+                     const uint8_t *src);
+
+    /* Returns 1 on success. */
+    int base64_decode_final(struct base64_decode_ctx *ctx);
 
     // Encoding functions
 
-    /// Calculate the buffer size required to hold the encoded form of
-    /// a string of length 'decodedLen' including all terminator bytes.
-    extern int base64_encode_len(int decodedLen);
+    /* Maximum length of output for base64_encode_update. NOTE: Doesn't
+     * include any padding that base64_encode_final may add. */
+    /* We have at most 4 buffered bits, and a total of (4 + length * 8) bits. */
+#   define BASE64_ENCODE_LENGTH(length) (((length) * 8 + 4)/6)
+
+    /* Maximum length of output generated by base64_encode_final. */
+#   define BASE64_ENCODE_FINAL_LENGTH 3
+
+    /* Exact length of output generated by base64_encode_raw, including
+     * padding.
+     */
+#   define BASE64_ENCODE_RAW_LENGTH(length) ((((length) + 2)/3)*4)
+
+    struct base64_encode_ctx
+    {
+        unsigned word;   /* Leftover bits */
+        unsigned bits;  /* Number of bits, always 0, 2, or 4. */
+    };
+
+    void base64_encode_init(struct base64_encode_ctx *ctx);
+
+    /// Encodes a single byte. Returns amount of output (always 1 or 2).
+    size_t base64_encode_single(struct base64_encode_ctx *ctx, uint8_t *dst, uint8_t src);
+
+    /* Returns the number of output characters. DST should point to an
+     * area of size at least BASE64_ENCODE_LENGTH(length).
+     */
+    size_t base64_encode_update(struct base64_encode_ctx *ctx, uint8_t *dst, size_t length, const uint8_t *src);
 
-    /// Base-64 encode a string into a given buffer.
-    /// Will not terminate the resulting string.
-    /// \return the number of bytes filled in result.
-    extern int base64_encode(char *result, int result_max_size, const char *data, int data_size);
-
-    /// Base-64 encode a string into a given buffer.
-    /// Will terminate the resulting string.
-    /// \return the number of bytes filled in result. Including the terminator.
-    extern int base64_encode_str(char *result, int result_max_size, const char *data, int data_size);
-
-    // Old encoder. Now a wrapper for the new. Takes a binary array of known length.
-    // Output is presented in a static buffer which will only remain valid until next call.
-    // Ensures a nul-terminated result. Will always return non-NULL.
-    extern const char *base64_encode_bin(const char *data, int len);
-
-    // Old encoder. Now a wrapper for the new.
-    // Output is presented in a static buffer which will only remain valid until next call.
-    // Ensures a nul-terminated result. Will always return non-NULL.
-    extern const char *old_base64_encode(const char *decoded);
+    /// DST should point to an area of size at least BASE64_ENCODE_FINAL_LENGTH
+    size_t base64_encode_final(struct base64_encode_ctx *ctx, uint8_t *dst);
 
 #ifdef __cplusplus
 }
 #endif
+
+#endif /* HAVE_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)
+
 #endif /* _SQUID_BASE64_H */

=== modified file 'lib/base64.c'
--- lib/base64.c	2014-09-02 01:08:58 +0000
+++ lib/base64.c	2014-12-17 19:51:15 +0000
@@ -1,214 +1,271 @@
 /*
  * Copyright (C) 1996-2014 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.
  */
 
 /*
- * Encoders adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments.
+ * Copied from Nettle 3.0 under GPLv2, with adjustments
  */
 
 #include "squid.h"
 #include "base64.h"
 
+#if !HAVE_NETTLE_BASE64_H
+
 #if HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
 
-static void base64_init(void);
+static const uint8_t encode_table[64] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz"
+  "0123456789+/";
+
+#define ENCODE(x) (encode_table[0x3F & (x)])
+
+static const signed char decode_table[0x100] =
+{
+  /* White space is HT, VT, FF, CR, LF and SPC */
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1,
+  -1,  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, -1, -1, -1, -1, -1,
+  -1, 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, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+#define TABLE_INVALID -1
+#define TABLE_SPACE -2
+#define TABLE_END -3
 
-static int base64_initialized = 0;
 #define BASE64_VALUE_SZ 256
-#define BASE64_RESULT_SZ 8192
 int base64_value[BASE64_VALUE_SZ];
-const char base64_code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-static void
-base64_init(void)
+void
+base64_decode_init(struct base64_decode_ctx *ctx)
+{
+    ctx->word = ctx->bits = ctx->padding = 0;
+}
+
+static int
+base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, uint8_t src)
 {
-    int i;
+    int data = decode_table[src];
 
-    for (i = 0; i < BASE64_VALUE_SZ; i++)
-        base64_value[i] = -1;
+    switch(data) {
+    default:
+        assert(data >= 0 && data < 0x40);
 
-    for (i = 0; i < 64; i++)
-        base64_value[(int) base64_code[i]] = i;
-    base64_value['='] = 0;
+        if (ctx->padding)
+            return -1;
 
-    base64_initialized = 1;
-}
+        ctx->word = ctx->word << 6 | data;
+        ctx->bits += 6;
 
-int
-base64_decode_len(const char *data)
-{
-    if (!data || !*data)
+        if (ctx->bits >= 8) {
+            ctx->bits -= 8;
+            dst[0] = ctx->word >> ctx->bits;
+            return 1;
+        } else
+            return 0;
+
+    case TABLE_INVALID:
+        return -1;
+
+    case TABLE_SPACE:
         return 0;
 
-    int terminatorLen = 0;
-    int dataLen = strlen(data);
-    int i;
-
-    for (i = dataLen - 1; i >= 0; i--) {
-        if (data[i] == '=')
-            terminatorLen++;
-        if (data[i] != '=')
-            break;
+    case TABLE_END:
+        /* There can be at most two padding characters. */
+        if (!ctx->bits || ctx->padding > 2)
+            return -1;
+
+        if (ctx->word & ( (1<<ctx->bits) - 1))
+            /* We shouldn't have any leftover bits */
+            return -1;
+
+        ctx->padding++;
+        ctx->bits -= 2;
+        return 0;
     }
-    return dataLen / 4 * 3 - terminatorLen;
 }
 
 int
-base64_decode(char *result, unsigned int result_size, const char *p)
+base64_decode_update(struct base64_decode_ctx *ctx,
+                     size_t *dst_length,
+                     uint8_t *dst,
+                     size_t src_length,
+                     const uint8_t *src)
 {
-    int j = 0;
-    int c;
-    long val;
-    if (!p || !result || result_size == 0)
-        return j;
-    if (!base64_initialized)
-        base64_init();
-    val = c = 0;
-    for (; *p; p++) {
-        unsigned int k = ((unsigned char) *p) % BASE64_VALUE_SZ;
-        if (base64_value[k] < 0)
-            continue;
-        val <<= 6;
-        val += base64_value[k];
-        if (++c < 4)
-            continue;
-        /* One quantum of four encoding characters/24 bit */
-        if (j+4 <= result_size) {
-            // Speed optimization: plenty of space, avoid some per-byte checks.
-            result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
-            result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
-            result[j++] = val & 0xff;		/* Low 8 bits */
-        } else {
-            // part-quantum goes a bit slower with per-byte checks
-            result[j++] = (val >> 16) & 0xff;	/* High 8 bits */
-            if (j == result_size)
-                return j;
-            result[j++] = (val >> 8) & 0xff;	/* Mid 8 bits */
-            if (j == result_size)
-                return j;
-            result[j++] = val & 0xff;		/* Low 8 bits */
+    size_t done;
+    size_t i;
+
+    for (i = 0, done = 0; i < src_length; i++) {
+        switch(base64_decode_single(ctx, dst + done, src[i])) {
+        case -1:
+            return 0;
+        case 1:
+            done++;
+            /* Fall through */
+        case 0:
+            break;
+        default:
+            abort();
         }
-        if (j == result_size)
-            return j;
-        val = c = 0;
     }
-    return j;
+
+    assert(done <= BASE64_DECODE_LENGTH(src_length));
+
+    *dst_length = done;
+    return 1;
 }
 
 int
-base64_encode_len(int len)
+base64_decode_final(struct base64_decode_ctx *ctx)
 {
-    // NP: some magic numbers + potential nil-terminator
-    return ((len + 2) / 3 * 4) + 1;
+  return ctx->bits == 0;
 }
 
-const char *
-old_base64_encode(const char *decoded_str)
+static void
+base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src)
 {
-    static char result[BASE64_RESULT_SZ];
-    base64_encode_str(result, sizeof(result), decoded_str, strlen(decoded_str));
-    return result;
+    const uint8_t *in = src + length;
+    uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
+
+    unsigned left_over = length % 3;
+
+    if (left_over) {
+        in -= left_over;
+        *--out = '=';
+        switch(left_over) {
+        case 1:
+            *--out = '=';
+            *--out = ENCODE(in[0] << 4);
+            break;
+
+        case 2:
+            *--out = ENCODE( in[1] << 2);
+            *--out = ENCODE((in[0] << 4) | (in[1] >> 4));
+            break;
+
+        default:
+            abort();
+        }
+        *--out = ENCODE(in[0] >> 2);
+    }
+
+    while (in > src) {
+        in -= 3;
+        *--out = ENCODE( in[2]);
+        *--out = ENCODE((in[1] << 2) | (in[2] >> 6));
+        *--out = ENCODE((in[0] << 4) | (in[1] >> 4));
+        *--out = ENCODE( in[0] >> 2);
+    }
+    assert(in == src);
+    assert(out == dst);
 }
 
-const char *
-base64_encode_bin(const char *decoded_str, int len)
+void
+base64_encode_init(struct base64_encode_ctx *ctx)
 {
-    static char result[BASE64_RESULT_SZ];
-    base64_encode_str(result, sizeof(result), decoded_str, len);
-    return result;
+  ctx->word = ctx->bits = 0;
 }
 
-int
-base64_encode_str(char *result, int result_max_size, const char *data, int data_size)
+/* Encodes a single byte. */
+size_t
+base64_encode_single(struct base64_encode_ctx *ctx,
+		     uint8_t *dst,
+		     uint8_t src)
 {
-    if (result_max_size < 1)
-        return 0;
-
-    int used = base64_encode(result, result_max_size, data, data_size);
-    /* terminate */
-    if (used >= result_max_size) {
-        result[result_max_size - 1] = '\0';
-        return result_max_size;
-    } else {
-        result[used++] = '\0';
+    unsigned done = 0;
+    unsigned word = ctx->word << 8 | src;
+    unsigned bits = ctx->bits + 8;
+
+    while (bits >= 6) {
+        bits -= 6;
+        dst[done++] = ENCODE(word >> bits);
     }
-    return used;
+
+    ctx->bits = bits;
+    ctx->word = word;
+
+    assert(done <= 2);
+
+    return done;
 }
 
-/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
-int
-base64_encode(char *result, int result_size, const char *data, int data_size)
+/* Returns the number of output characters. DST should point to an
+ * area of size at least BASE64_ENCODE_LENGTH(length). */
+size_t
+base64_encode_update(struct base64_encode_ctx *ctx,
+		     uint8_t *dst,
+		     size_t length,
+		     const uint8_t *src)
 {
-    int bits = 0;
-    int char_count = 0;
-    int out_cnt = 0;
+    size_t done = 0;
+    size_t left = length;
+    unsigned left_over;
+    size_t bulk;
+
+    while (ctx->bits && left) {
+        left--;
+        done += base64_encode_single(ctx, dst + done, *src++);
+    }
 
-    if (!data || !*data || !result || result_size < 1 || data_size < 1)
-        return 0;
+    left_over = left % 3;
+    bulk = left - left_over;
 
-    if (!base64_initialized)
-        base64_init();
+    if (bulk) {
+        assert(!(bulk % 3));
 
-    while (data_size--) {
-        int c = (unsigned char) *data++;
-        bits += c;
-        char_count++;
-        if (char_count == 3) {
-            if (out_cnt >= result_size)
-                break;
-            if (out_cnt+4 <= result_size) {
-                result[out_cnt++] = base64_code[bits >> 18];
-                result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-                result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-                result[out_cnt++] = base64_code[bits & 0x3f];
-            } else {
-                // part-quantum goes a bit slower with per-byte checks
-                result[out_cnt++] = base64_code[bits >> 18];
-                if (out_cnt >= result_size)
-                    break;
-                result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-                if (out_cnt >= result_size)
-                    break;
-                result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-                if (out_cnt >= result_size)
-                    break;
-                result[out_cnt++] = base64_code[bits & 0x3f];
-            }
-            bits = 0;
-            char_count = 0;
-        } else {
-            bits <<= 8;
-        }
+        base64_encode_raw(dst + done, bulk, src);
+        done += BASE64_ENCODE_RAW_LENGTH(bulk);
+        src += bulk;
+        left = left_over;
     }
-    if (char_count != 0) {
-        bits <<= 16 - (8 * char_count);
-        if (out_cnt >= result_size)
-            return result_size;
-        result[out_cnt++] = base64_code[bits >> 18];
-        if (out_cnt >= result_size)
-            return result_size;
-        result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
-        if (char_count == 1) {
-            if (out_cnt >= result_size)
-                return result_size;
-            result[out_cnt++] = '=';
-            if (out_cnt >= result_size)
-                return result_size;
-            result[out_cnt++] = '=';
-        } else {
-            if (out_cnt >= result_size)
-                return result_size;
-            result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
-            if (out_cnt >= result_size)
-                return result_size;
-            result[out_cnt++] = '=';
-        }
+
+    while (left) {
+        left--;
+        done += base64_encode_single(ctx, dst + done, *src++);
     }
-    return (out_cnt >= result_size?result_size:out_cnt);
+
+    assert(done <= BASE64_ENCODE_LENGTH(length));
+
+    return done;
 }
+
+/* DST should point to an area of size at least
+ * BASE64_ENCODE_FINAL_SIZE */
+size_t
+base64_encode_final(struct base64_encode_ctx *ctx,
+		    uint8_t *dst)
+{
+    unsigned done = 0;
+    unsigned bits = ctx->bits;
+
+    if (bits) {
+        dst[done++] = ENCODE(ctx->word << (6 - ctx->bits));
+        for (; bits < 6; bits += 2)
+            dst[done++] = '=';
+
+        ctx->bits = 0;
+    }
+
+    assert(done <= BASE64_ENCODE_FINAL_LENGTH);
+    return done;
+}
+
+#endif /* HAVE_NETTLE_BASE64_H */

=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2014-12-01 04:05:48 +0000
+++ src/HttpHeader.cc	2014-12-18 10:49:26 +0000
@@ -1509,41 +1509,47 @@
     if (!field)			/* no authorization field */
         return NULL;
 
     l = strlen(auth_scheme);
 
     if (!l || strncasecmp(field, auth_scheme, l))	/* wrong scheme */
         return NULL;
 
     field += l;
 
     if (!xisspace(*field))	/* wrong scheme */
         return NULL;
 
     /* skip white space */
     for (; field && xisspace(*field); ++field);
 
     if (!*field)		/* no authorization cookie */
         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);
+    size_t 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;
 }
 
 ETag
 HttpHeader::getETag(http_hdr_type id) const
 {
     ETag etag = {NULL, -1};
     HttpHeaderEntry *e;
     assert(Headers[id].type == ftETag);		/* must be of an appropriate type */
 
     if ((e = findEntry(id)))
         etagParseInit(&etag, e->value.termedBuf());
 
     return etag;
 }
 
 TimeOrTag
 HttpHeader::getTimeOrTag(http_hdr_type id) const
 {

=== modified file 'src/adaptation/icap/ModXact.cc'
--- src/adaptation/icap/ModXact.cc	2014-09-13 13:59:43 +0000
+++ src/adaptation/icap/ModXact.cc	2014-12-11 13:23:14 +0000
@@ -1343,45 +1343,48 @@
     buf.Printf("%s " SQUIDSTRINGPH " ICAP/1.0\r\n", s.methodStr(), SQUIDSTRINGPRINT(s.uri));
     buf.Printf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(s.host), s.port);
     buf.Printf("Date: %s\r\n", mkrfc1123(squid_curtime));
 
     if (!TheConfig.reuse_connections)
         buf.Printf("Connection: close\r\n");
 
     const HttpRequest *request = &virginRequest();
 
     // we must forward "Proxy-Authenticate" and "Proxy-Authorization"
     // as ICAP headers.
     if (virgin.header->header.has(HDR_PROXY_AUTHENTICATE)) {
         String vh=virgin.header->header.getByName("Proxy-Authenticate");
         buf.Printf("Proxy-Authenticate: " SQUIDSTRINGPH "\r\n",SQUIDSTRINGPRINT(vh));
     }
 
     if (virgin.header->header.has(HDR_PROXY_AUTHORIZATION)) {
         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
     if (Adaptation::Config::masterx_shared_name) {
         Adaptation::History::Pointer ah = request->adaptHistory(false);
         if (ah != NULL) {
             String name, value;
             if (ah->getXxRecord(name, value)) {
                 buf.Printf(SQUIDSTRINGPH ": " SQUIDSTRINGPH "\r\n",
                            SQUIDSTRINGPRINT(name), SQUIDSTRINGPRINT(value));
             }
         }
     }
 
     buf.Printf("Encapsulated: ");
 
     MemBuf httpBuf;
 
     httpBuf.init();
 
@@ -1493,49 +1496,58 @@
     // writing Allow/204     means we will honor 204 outside preview
     // writing Allow:206     means we will honor 206 inside preview
     // writing Allow:204,206 means we will honor 206 outside preview
     const char *allowHeader = NULL;
     if (allow204out && allow206)
         allowHeader = "Allow: 204, 206\r\n";
     else if (allow204out)
         allowHeader = "Allow: 204\r\n";
     else if (allow206)
         allowHeader = "Allow: 206\r\n";
 
     if (allowHeader) { // may be nil if only allow204in is true
         buf.append(allowHeader, strlen(allowHeader));
         debugs(93,5, HERE << "Will write " << allowHeader);
     }
 }
 
 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
 }
 
 void Adaptation::Icap::ModXact::encapsulateHead(MemBuf &icapBuf, const char *section, MemBuf &httpBuf, const HttpMsg *head)
 {
     // update ICAP header
     icapBuf.Printf("%s=%d, ", section, (int) httpBuf.contentSize());
 
     // begin cloning
     HttpMsg::Pointer headClone;
 
     if (const HttpRequest* old_request = dynamic_cast<const HttpRequest*>(head)) {
         HttpRequest::Pointer new_request(new HttpRequest);
         Must(old_request->canonical);
         urlParse(old_request->method, old_request->canonical, new_request.getRaw());
         new_request->http_ver = old_request->http_ver;
         headClone = new_request.getRaw();
     } else if (const HttpReply *old_reply = dynamic_cast<const HttpReply*>(head)) {
         HttpReply::Pointer new_reply(new HttpReply);

=== modified file 'src/auth/digest/Config.cc'
--- src/auth/digest/Config.cc	2014-12-01 04:05:48 +0000
+++ src/auth/digest/Config.cc	2014-12-17 13:35:44 +0000
@@ -85,41 +85,45 @@
 static void authenticateDigestNonceCacheCleanup(void *data);
 static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);
 static void authenticateDigestNonceDelete(digest_nonce_h * nonce);
 static void authenticateDigestNonceSetup(void);
 static void authDigestNonceEncode(digest_nonce_h * nonce);
 static void authDigestNonceLink(digest_nonce_h * nonce);
 #if NOT_USED
 static int authDigestNonceLinks(digest_nonce_h * nonce);
 #endif
 static void authDigestNonceUserUnlink(digest_nonce_h * nonce);
 
 static void
 authDigestNonceEncode(digest_nonce_h * nonce)
 {
     if (!nonce)
         return;
 
     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 *
 authenticateDigestNonceNew(void)
 {
     digest_nonce_h *newnonce = static_cast < digest_nonce_h * >(digest_nonce_pool->alloc());
 
     /* NONCE CREATION - NOTES AND REASONING. RBC 20010108
      * === EXCERPT FROM RFC 2617 ===
      * The contents of the nonce are implementation dependent. The quality
      * of the implementation depends on a good choice. A nonce might, for
      * example, be constructed as the base 64 encoding of
      *
      * time-stamp H(time-stamp ":" ETag ":" private-key)
      *
      * where time-stamp is a server-generated time or other non-repeating
      * value, ETag is the value of the HTTP ETag header associated with
      * the requested entity, and private-key is data known only to the
      * server.  With a nonce of this form a server would recalculate the
      * hash portion after receiving the client authentication header and

=== modified file 'src/http.cc'
--- src/http.cc	2014-12-11 08:35:32 +0000
+++ src/http.cc	2014-12-17 18:10:45 +0000
@@ -1591,93 +1591,98 @@
         return;
 
     /* Maybe already dealt with? */
     if (hdr_out->has(header))
         return;
 
     /* Nothing to do here for PASSTHRU */
     if (strcmp(request->peer_login, "PASSTHRU") == 0)
         return;
 
     /* PROXYPASS is a special case, single-signon to servers with the proxy password (basic only) */
     if (flags.originpeer && strcmp(request->peer_login, "PROXYPASS") == 0 && hdr_in->has(HDR_PROXY_AUTHORIZATION)) {
         const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION);
 
         if (auth && strncasecmp(auth, "basic ", 6) == 0) {
             hdr_out->putStr(header, auth);
             return;
         }
     }
 
+    uint8_t loginbuf[base64_encode_len(MAX_LOGIN_SZ)];
+    size_t 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())
             username = request->extacl_user.termedBuf();
 #if USE_AUTH
         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;
     }
 
     /* external_acl provided credentials */
     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
     if (strcmp(request->peer_login, "PASS") == 0)
         return;
 
     /* Kerberos login to peer */
 #if HAVE_AUTH_MODULE_NEGOTIATE && HAVE_KRB5 && HAVE_GSSAPI
     if (strncmp(request->peer_login, "NEGOTIATE",strlen("NEGOTIATE")) == 0) {
         char *Token=NULL;
         char *PrincipalName=NULL,*p;
         if ((p=strchr(request->peer_login,':')) != NULL ) {
             PrincipalName=++p;
         }
         Token = peer_proxy_negotiate_auth(PrincipalName, request->peer_host);
         if (Token) {
             httpHeaderPutStrf(hdr_out, header, "Negotiate %s",Token);
         }
         return;
     }
 #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;
 }
 
 /*
  * build request headers and append them to a given MemBuf
  * used by buildRequestPrefix()
  * note: initialised the HttpHeader, the caller is responsible for Clean()-ing
  */
 void
 HttpStateData::httpBuildRequestHeader(HttpRequest * request,
                                       StoreEntry * entry,
                                       const AccessLogEntryPointer &al,
                                       HttpHeader * hdr_out,
                                       const HttpStateFlags &flags)
 {
     /* building buffer for complex strings */
 #define BBUF_SZ (MAX_URL+32)
     LOCAL_ARRAY(char, bbuf, BBUF_SZ);
     LOCAL_ARRAY(char, ntoabuf, MAX_IPSTRLEN);
     const HttpHeader *hdr_in = &request->header;
@@ -1779,43 +1784,48 @@
     }
     /** If set to DELETE - do not copy through. */
 
     /* append Host if not there already */
     if (!hdr_out->has(HDR_HOST)) {
         if (request->peer_domain) {
             hdr_out->putStr(HDR_HOST, request->peer_domain);
         } else if (request->port == urlDefaultPort(request->url.getScheme())) {
             /* use port# only if not default */
             hdr_out->putStr(HDR_HOST, request->GetHost());
         } else {
             httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
                               request->GetHost(),
                               (int) request->port);
         }
     }
 
     /* append Authorization if known in URL, not in header and going direct */
     if (!hdr_out->has(HDR_AUTHORIZATION)) {
         if (!request->flags.proxying && !request->url.userInfo().isEmpty()) {
-            static char result[MAX_URL*2]; // should be big enough for a single URI segment
-            if (base64_encode_str(result, sizeof(result)-1, request->url.userInfo().rawContent(), request->url.userInfo().length()) < static_cast<int>(sizeof(result)-1))
-                httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", result);
+            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);
+            size_t blen = base64_encode_update(&ctx, result, request->url.userInfo().length(), reinterpret_cast<const uint8_t*>(request->url.userInfo().rawContent()));
+            blen += base64_encode_final(&ctx, result+blen);
+            result[blen] = '\0';
+            if (blen)
+                httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %.*s", blen, result);
         }
     }
 
     /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */
     httpFixupAuthentication(request, hdr_in, hdr_out, flags);
 
     /* append Cache-Control, add max-age if not there already */
     {
         HttpHdrCc *cc = hdr_in->getCc();
 
         if (!cc)
             cc = new HttpHdrCc();
 
 #if 0 /* see bug 2330 */
         /* Set no-cache if determined needed but not found */
         if (request->flags.nocache)
             EBIT_SET(cc->mask, CC_NO_CACHE);
 #endif
 
         /* Add max-age only without no-cache */

=== modified file 'src/peer_proxy_negotiate_auth.cc'
--- src/peer_proxy_negotiate_auth.cc	2014-09-17 13:21:07 +0000
+++ src/peer_proxy_negotiate_auth.cc	2014-12-17 13:34:19 +0000
@@ -535,40 +535,44 @@
 
         if (check_gss_err(major_status, minor_status, "gss_import_name()"))
             goto cleanup;
 
         debugs(11, 5, HERE << "Initialize gss security context");
         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;
 
         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:
         gss_delete_sec_context(&minor_status, &gss_context, NULL);
         gss_release_buffer(&minor_status, &service);
         gss_release_buffer(&minor_status, &input_token);
         gss_release_buffer(&minor_status, &output_token);
         gss_release_name(&minor_status, &server_name);
 
         return token;
     }
 
 #ifdef __cplusplus
 }
 #endif
 #endif /* HAVE_KRB5 && HAVE_GSSAPI */

=== modified file 'tools/cachemgr.cc'
--- tools/cachemgr.cc	2014-09-25 13:33:18 +0000
+++ tools/cachemgr.cc	2014-12-18 10:48:17 +0000
@@ -1060,62 +1060,73 @@
 static void
 make_pub_auth(cachemgr_request * req)
 {
     static char buf[1024];
     safe_free(req->pub_auth);
     debug("cmgr: encoding for pub...\n");
 
     if (!req->passwd || !strlen(req->passwd))
         return;
 
     /* host | time | user | passwd */
     const int bufLen = snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
                                 req->hostname,
                                 (int) now,
                                 req->user_name ? req->user_name : "",
                                 req->passwd);
     debug("cmgr: pre-encoded for pub: %s\n", buf);
 
     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);
 }
 
 static void
 decode_pub_auth(cachemgr_request * req)
 {
     char *buf;
     const char *host_name;
     const char *time_str;
     const char *user_name;
     const char *passwd;
 
     debug("cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth));
     safe_free(req->passwd);
 
     if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
         return;
 
-    const int decodedLen = base64_decode_len(req->pub_auth);
+    size_t 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");
 
     /* parse ( a lot of memory leaks, but that is cachemgr style :) */
     if ((host_name = strtok(buf, "|")) == NULL) {
         xfree(buf);
         return;
     }
 
     debug("cmgr: decoded host: '%s'\n", host_name);
 
     if ((time_str = strtok(NULL, "|")) == NULL) {
         xfree(buf);
         return;
     }
 
     debug("cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
 
     if ((user_name = strtok(NULL, "|")) == NULL) {
         xfree(buf);
@@ -1161,48 +1172,52 @@
     safe_free(req->pub_auth);
 }
 
 static const char *
 make_auth_header(const cachemgr_request * req)
 {
     static char buf[1024];
     size_t stringLength = 0;
 
     if (!req->passwd)
         return "";
 
     int bufLen = snprintf(buf, sizeof(buf), "%s:%s",
                           req->user_name ? req->user_name : "",
                           req->passwd);
 
     int encodedLen = base64_encode_len(bufLen);
     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;
 }
 
 static int
 check_target_acl(const char *hostname, int port)
 {
     char config_line[BUFSIZ];
     FILE *fp = NULL;
     int ret = 0;
     fp = fopen("cachemgr.conf", "r");
 
     if (fp == NULL)
         fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
 
     if (fp == NULL) {
 #ifdef CACHEMGR_HOSTNAME_DEFINED
 
         if (strcmp(hostname, CACHEMGR_HOSTNAME) == 0 && port == CACHE_HTTP_PORT)

=== modified file 'tools/squidclient/gssapi_support.cc'
--- tools/squidclient/gssapi_support.cc	2014-09-13 13:20:21 +0000
+++ tools/squidclient/gssapi_support.cc	2014-12-17 15:53:44 +0000
@@ -85,64 +85,75 @@
  *
  * \return base64 encoded token if successful,
  *         string "ERROR" if unsuccessful
  */
 char *
 GSSAPI_token(const char *server)
 {
     OM_uint32 major_status, minor_status;
     gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
     gss_name_t server_name = GSS_C_NO_NAME;
     gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
     char *token = NULL;
 
     setbuf(stdout, NULL);
     setbuf(stdin, NULL);
 
     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';
     }
     service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
     snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
     service.length = strlen((char *) service.value);
 
     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()")) {
 
         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()")) {
+        if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()") && output_token.length) {
 
-            if (output_token.length)
-                token = (char *) base64_encode_bin((const char *) output_token.value, 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';
+
+            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);
     gss_release_buffer(&minor_status, &output_token);
     gss_release_name(&minor_status, &server_name);
 
     return token;
 }
 
 #endif /* HAVE_GSSAPI */

=== modified file 'tools/squidclient/squidclient.cc'
--- tools/squidclient/squidclient.cc	2014-09-13 13:20:21 +0000
+++ tools/squidclient/squidclient.cc	2014-12-17 15:55:28 +0000
@@ -400,82 +400,95 @@
         if (reload) {
             snprintf(buf, BUFSIZ, "Cache-Control: no-cache\r\n");
             strcat(msg, buf);
         }
         if (put_fd > 0) {
             snprintf(buf, BUFSIZ, "Content-length: %" PRId64 "\r\n", (int64_t) sb.st_size);
             strcat(msg, buf);
         }
         if (opt_noaccept == 0) {
             snprintf(buf, BUFSIZ, "Accept: */*\r\n");
             strcat(msg, buf);
         }
         if (ims) {
             snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims));
             strcat(msg, buf);
         }
         if (max_forwards > -1) {
             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;
 #if HAVE_GETPASS
             if (!password)
                 password = getpass("Proxy password: ");
 #endif
             if (!password) {
                 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) {
             const char *user = www_user;
             const char *password = www_password;
 #if HAVE_GETPASS
             if (!password)
                 password = getpass("WWW password: ");
 #endif
             if (!password) {
                 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;
         }
 #endif
 
         /* HTTP/1.0 may need keep-alive explicitly */
         if (strcmp(version, "1.0") == 0 && keep_alive)
             strcat(msg, "Connection: keep-alive\r\n");
 
         /* HTTP/1.1 may need close explicitly */
         if (!keep_alive)
             strcat(msg, "Connection: close\r\n");
 
         strcat(msg, extra_hdrs);
         strcat(msg, "\r\n");
     }
 
     debugVerbose(1, "Request:" << std::endl << msg << std::endl << ".");
 
     uint32_t loops = Ping::Init();



More information about the squid-dev mailing list