]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Crypto-NG: Base64 crypto replacement
authorAmos Jeffries <squid3@treenet.co.nz>
Tue, 30 Dec 2014 09:09:27 +0000 (01:09 -0800)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 30 Dec 2014 09:09:27 +0000 (01:09 -0800)
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.

18 files changed:
CREDITS
configure.ac
helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
helpers/negotiate_auth/kerberos/negotiate_kerberos_auth_test.cc
helpers/negotiate_auth/kerberos/negotiate_kerberos_pac.cc
helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
helpers/ntlm_auth/fake/ntlm_fake_auth.cc
helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc
include/base64.h
lib/base64.c
src/HttpHeader.cc
src/adaptation/icap/ModXact.cc
src/auth/digest/Config.cc
src/http.cc
src/peer_proxy_negotiate_auth.cc
tools/cachemgr.cc
tools/squidclient/gssapi_support.cc
tools/squidclient/squidclient.cc

diff --git a/CREDITS b/CREDITS
index c7ae1188a16c058942d089ec57277e4d05d947d4..4099183a7915c1dc30012f0a70ca38d4b8510237 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1482,6 +1482,41 @@ lib/snmplib/snmp_vars.c:
 
 ==============================================================================
 
+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:
 
index bcf67bbf68817cbca7696a1cbed7d54573dedfc8..01ea31261a4e3783e95599d4e21faf1b50528fc7 100644 (file)
@@ -1199,7 +1199,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 bf209decf621fbe63e8d0ddf87a32b39068618f1..ef2c780b2237c6a99337e0f3a0567c0f884e8eff 100644 (file)
@@ -656,12 +656,22 @@ main(int argc, char *const argv[])
             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))) {
@@ -708,14 +718,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 c5031ceb2aea7cab491be6d627bf1d6d06db7cd3..d45f8ad189a427d65af6851a1e2a110b3c82bc58 100644 (file)
@@ -186,26 +186,25 @@ 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;
-
-    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_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()") && 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 d5078b78ebe5b8ab875c6f7c8c88826962ac028d..6f04f998441c0f28155e99fb4c5da77158e78b44 100644 (file)
@@ -230,10 +230,17 @@ getdomaingids(char *ad_groups, uint32_t DomainLogonId, char **Rids, uint32_t Gro
                           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);
         }
 
@@ -302,10 +309,18 @@ getextrasids(char *ad_groups, uint32_t ExtraSids, uint32_t SidCount)
                               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 ef6a5487a4254d2aa6d88b17392aa6702bf1bb62..82f4c826888b88785f58ba76b9df48c4c50302f9 100644 (file)
@@ -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);
+        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))) {
@@ -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 ecdc5da32497d0ae67b8ccaa8fdd046a73a3d64a..1e74f2898edbc3c2fac3cf88dea2ac7db09a0194 100644 (file)
@@ -131,14 +131,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);
@@ -156,13 +155,19 @@ 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);
+        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';
@@ -185,13 +190,20 @@ 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);
+            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=");
index 48a76c9ac4726ca35d8cffd902ca1c1d30c97b52..d084a0454545f496f2bb383a2c8e78323cb021c0 100644 (file)
@@ -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"
@@ -181,6 +182,7 @@ make_challenge(char *domain, char *domain_controller)
     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 |
@@ -189,8 +191,22 @@ make_challenge(char *domain, char *domain_controller)
                      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
@@ -479,10 +495,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);
+        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. */
index 87b3e703574e3159d779932f6a78d8b15d88e636..35cc7ef710b019b85e1bb21c29ae13d0b85f6c26 100644 (file)
@@ -9,52 +9,88 @@
 #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);
+/// 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);
 
-/// 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);
+/* 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)
 
-/// 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);
+/* Maximum length of output generated by base64_encode_final. */
+#   define BASE64_ENCODE_FINAL_LENGTH 3
 
-/// 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);
+/* Exact length of output generated by base64_encode_raw, including
+ * padding.
+ */
+#   define BASE64_ENCODE_RAW_LENGTH(length) ((((length) + 2)/3)*4)
 
-// 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);
+struct base64_encode_ctx
+{
+    unsigned word;   /* Leftover bits */
+    unsigned bits;  /* Number of bits, always 0, 2, or 4. */
+};
 
-// 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);
+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);
+
+/// 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 */
 
index a9d19e31f6739c6e7b42a6661e895584785b7353..3926045fe256e7752c12808db080282df0aecb1d 100644 (file)
  */
 
 /*
- * 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+/";
 
-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+/";
+#define ENCODE(x) (encode_table[0x3F & (x)])
 
-static void
-base64_init(void)
+static const signed char decode_table[0x100] =
 {
-    int i;
+    /* 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,
+};
 
-    for (i = 0; i < BASE64_VALUE_SZ; i++)
-        base64_value[i] = -1;
+#define TABLE_INVALID -1
+#define TABLE_SPACE -2
+#define TABLE_END -3
 
-    for (i = 0; i < 64; i++)
-        base64_value[(int) base64_code[i]] = i;
-    base64_value['='] = 0;
+#define BASE64_VALUE_SZ 256
+int base64_value[BASE64_VALUE_SZ];
 
-    base64_initialized = 1;
+void
+base64_decode_init(struct base64_decode_ctx *ctx)
+{
+    ctx->word = ctx->bits = ctx->padding = 0;
 }
 
-int
-base64_decode_len(const char *data)
+static int
+base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, uint8_t src)
 {
-    if (!data || !*data)
+    int data = decode_table[src];
+
+    switch(data) {
+    default:
+        assert(data >= 0 && data < 0x40);
+
+        if (ctx->padding)
+            return -1;
+
+        ctx->word = ctx->word << 6 | data;
+        ctx->bits += 6;
+
+        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;
+    case TABLE_END:
+        /* There can be at most two padding characters. */
+        if (!ctx->bits || ctx->padding > 2)
+            return -1;
 
-    for (i = dataLen - 1; i >= 0; i--) {
-        if (data[i] == '=')
-            terminatorLen++;
-        if (data[i] != '=')
-            break;
+        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;
+    unsigned done = 0;
+    unsigned word = ctx->word << 8 | src;
+    unsigned bits = ctx->bits + 8;
 
-    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';
+    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;
 
-    if (!data || !*data || !result || result_size < 1 || data_size < 1)
-        return 0;
+    while (ctx->bits && left) {
+        left--;
+        done += base64_encode_single(ctx, dst + done, *src++);
+    }
 
-    if (!base64_initialized)
-        base64_init();
-
-    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;
-        }
+    left_over = left % 3;
+    bulk = left - left_over;
+
+    if (bulk) {
+        assert(!(bulk % 3));
+
+        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 */
+
index 4d24035a8c619eca017ee80fda4438649c3bcf92..9a8b92e8a0d939758b33cec4a1a5006637d353d2 100644 (file)
@@ -1526,7 +1526,13 @@ HttpHeader::getAuth(http_hdr_type id, const char *auth_scheme) const
         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;
 }
index 51c108a8a10e2a9eaaebb9bac207c2e6082a41fc..f85092e754454bad0cea2b2bcccbe53aa4506951 100644 (file)
@@ -1360,11 +1360,14 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
         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,15 +1513,24 @@ void Adaptation::Icap::ModXact::makeAllowHeader(MemBuf &buf)
 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 5e08a3847d1026c02338f223df077cd32d79362b..efee47df3c9b3e36f45677824d3976c5088d6b18 100644 (file)
@@ -102,7 +102,11 @@ authDigestNonceEncode(digest_nonce_h * nonce)
     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 a4250c0a11a57e6c54ad4d726381eb185a83310d..75dd9a995af37117b6a67e176b5b4a5c88704024 100644 (file)
@@ -1608,9 +1608,13 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
         }
     }
 
+    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())
@@ -1620,10 +1624,10 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
             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;
     }
 
@@ -1631,12 +1635,12 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
     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
@@ -1659,8 +1663,9 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
     }
 #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;
 }
 
@@ -1796,9 +1801,14 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request,
     /* 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);
         }
     }
 
index 253c64cec1201aa579148d3c8e06efe7bd7f3b60..45f2248491ec701ced0cc0d8ed67d2bd52c7d99d 100644 (file)
@@ -553,10 +553,14 @@ char *peer_proxy_negotiate_auth(char *principal_name, char *proxy) {
 
     debugs(11, 5, HERE << "Got token with length " << output_token.length);
     if (output_token.length) {
-
-        token =
-            (char *) base64_encode_bin((const char *) output_token.value,
-                                       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 = reinterpret_cast<char*>(b64buf);
     }
 
 cleanup:
index 2073d5c0d8b85455657343c46d95e4d97714bc63..49b5ed081c5894a60662f0980f35e0685e448999 100644 (file)
@@ -1077,7 +1077,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);
 }
 
@@ -1096,9 +1100,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);
+    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");
 
@@ -1178,14 +1189,18 @@ make_auth_header(const cachemgr_request * req)
     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 5498bb7885d6572374b619fe68dcd35d9a72d746..5e28cc80a9b17874dcb4ca8b332008ddc18dff8c 100644 (file)
@@ -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 0f72bd8604bd2aff94e78f8acecd0283cc2be1c1..54ded3df33479c792bb66f950ebadf35ac4330ef 100644 (file)
@@ -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;
         }