]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Convert base64 code to work with dbuffs/sbuffs
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 20 May 2021 20:35:38 +0000 (22:35 +0200)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 21 May 2021 14:30:43 +0000 (16:30 +0200)
src/lib/eap_aka_sim/id.c
src/lib/server/password.c
src/lib/server/tmpl_tokenize.c
src/lib/unlang/xlat_builtin.c
src/lib/util/base64.c
src/lib/util/base64.h
src/lib/util/sbuff.h
src/modules/rlm_pap/rlm_pap.c
src/tests/keywords/base64

index c40b95ec347e07b27993045411b01ef6f95ec6e3..51bb2b6828daa8e5f21e1962f95f52dea0928a40 100644 (file)
@@ -514,19 +514,19 @@ int fr_aka_sim_id_3gpp_pseudonym_encrypt(char out[AKA_SIM_3GPP_PSEUDONYM_LEN + 1
        /*
         *      Consume tag (6 bits) + key_ind (4 bits) + encr[0] (8 bits) = 18 bits (or 3 bytes of b64)
         */
-       *out_p++ = fr_base64_str[tag & 0x3f];                                                   /* 6 bits tag */
-       *out_p++ = fr_base64_str[((key_ind & 0x0f) << 2) | ((u_p[0] & 0xc0) >> 6)];             /* 4 bits key_ind + 2 high bits encr[0] */
-       *out_p++ = fr_base64_str[u_p[0] & 0x3f];                                                /* 6 low bits of encr[0] */
+       *out_p++ = fr_base64_alphabet_encode[tag & 0x3f];                                                       /* 6 bits tag */
+       *out_p++ = fr_base64_alphabet_encode[((key_ind & 0x0f) << 2) | ((u_p[0] & 0xc0) >> 6)];         /* 4 bits key_ind + 2 high bits encr[0] */
+       *out_p++ = fr_base64_alphabet_encode[u_p[0] & 0x3f];                                            /* 6 low bits of encr[0] */
        u_p++;
 
        /*
         *      Consume 3 bytes of input for 4 bytes of b64 (5 iterations)
         */
        while (u_p < u_end) {
-               *out_p++ = fr_base64_str[(u_p[0] & 0xfc) >> 2];                                 /* 6 high bits of p[0] */
-               *out_p++ = fr_base64_str[((u_p[0] & 0x03) << 4) | ((u_p[1] & 0xf0) >> 4)];      /* 2 low bits of p[0] + 4 high bits of p[1] */
-               *out_p++ = fr_base64_str[((u_p[1] & 0x0f) << 2) | ((u_p[2] & 0xc0) >> 6)];      /* 4 low bits of p[1] + 2 high bits of p[2] */
-               *out_p++ = fr_base64_str[u_p[2] & 0x3f];                                        /* 6 low bits of p[2] */
+               *out_p++ = fr_base64_alphabet_encode[(u_p[0] & 0xfc) >> 2];                                     /* 6 high bits of p[0] */
+               *out_p++ = fr_base64_alphabet_encode[((u_p[0] & 0x03) << 4) | ((u_p[1] & 0xf0) >> 4)];  /* 2 low bits of p[0] + 4 high bits of p[1] */
+               *out_p++ = fr_base64_alphabet_encode[((u_p[1] & 0x0f) << 2) | ((u_p[2] & 0xc0) >> 6)];  /* 4 low bits of p[1] + 2 high bits of p[2] */
+               *out_p++ = fr_base64_alphabet_encode[u_p[2] & 0x3f];                                    /* 6 low bits of p[2] */
                u_p += 3;
        }
        if ((out_p - out) != AKA_SIM_3GPP_PSEUDONYM_LEN) {
index bf1bc466d1ebfd622ed1553f380bb60e8da8c5a1..e3072772b3b0ac7882d928867aeff99f541550bb 100644 (file)
@@ -434,8 +434,8 @@ static ssize_t normify(normalise_t *action, uint8_t *buffer, size_t bufflen,
        if ((len * 3) >= ((min_len * 4))) {
                ssize_t decoded;
 
-               decoded = fr_base64_decode(buffer, bufflen, known_good, len);
-               if (decoded < 0) return 0;
+               decoded = fr_base64_decode(&FR_DBUFF_TMP(buffer, bufflen), &FR_SBUFF_IN(known_good, len), true, true);
+               if (decoded <= 0) return 0;
                if (decoded >= (ssize_t) min_len) {
                        if (action) *action = NORMALISED_B64;
                        return decoded;
index 1391eab457dbc13b6a7bb2afdb57fe59f6cb0ad6..a20f878167b4b2fdc7cc144d4b2b8c57af294029 100644 (file)
@@ -2241,7 +2241,7 @@ static ssize_t tmpl_afrom_ipv4_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t
        /*
         *      Check for char sequence
         *
-        *      xxx.xxxx.xxx.xxx
+        *      xxx.xxx.xxx.xxx
         */
        if (!(fr_sbuff_out(NULL, &octet, &our_in) && fr_sbuff_next_if_char(&our_in, '.') &&
              fr_sbuff_out(NULL, &octet, &our_in) && fr_sbuff_next_if_char(&our_in, '.') &&
index fba3ca6ed998b5c014621ef38433c2d23aa45a26..d821cd6f68fdc9a96c2c0bfb615238a68996610d 100644 (file)
@@ -1558,13 +1558,13 @@ static xlat_action_t xlat_func_base64_encode(TALLOC_CTX *ctx, fr_dcursor_t *out,
                return XLAT_ACTION_FAIL;
        }
 
-       elen = fr_base64_encode(buff, alen + 1, in->vb_octets, in->vb_length);
+       elen = fr_base64_encode(&FR_SBUFF_OUT(buff, talloc_array_length(buff)),
+                               &FR_DBUFF_TMP(in->vb_octets, in->vb_length), true);
        if (elen < 0) {
                RPEDEBUG("Base64 encoding failed");
                talloc_free(vb);
                return XLAT_ACTION_FAIL;
        }
-
        fr_assert((size_t)elen <= alen);
        vb->tainted = in->tainted;
        fr_dcursor_append(out, vb);
@@ -1593,23 +1593,26 @@ static xlat_action_t xlat_func_base64_decode(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                             fr_value_box_list_t *args)
 {
        size_t          alen;
-       ssize_t         declen;
+       ssize_t         declen = 0;
        uint8_t         *decbuf;
        fr_value_box_t  *vb;
        fr_value_box_t  *in = fr_dlist_head(args);
 
        alen = FR_BASE64_DEC_LENGTH(in->vb_length);
-
        MEM(vb = fr_value_box_alloc_null(ctx));
-       MEM(fr_value_box_mem_alloc(vb, &decbuf, vb, NULL, alen, in->tainted) == 0);
-       declen = fr_base64_decode(decbuf, alen, in->vb_strvalue, in->vb_length);
-       if (declen < 0) {
-               REDEBUG("Base64 string invalid");
-               talloc_free(vb);
-               return XLAT_ACTION_FAIL;
+       if (alen > 0) {
+               MEM(fr_value_box_mem_alloc(vb, &decbuf, vb, NULL, alen, in->tainted) == 0);
+               declen = fr_base64_decode(&FR_DBUFF_TMP(decbuf, alen),
+                                         &FR_SBUFF_IN(in->vb_strvalue, in->vb_length), true, true);
+               if (declen < 0) {
+                       RPEDEBUG("Base64 string invalid");
+                       talloc_free(vb);
+                       return XLAT_ACTION_FAIL;
+               }
+
+               MEM(fr_value_box_mem_realloc(vb, NULL, vb, declen) == 0);
        }
 
-       MEM(fr_value_box_mem_realloc(vb, NULL, vb, declen) == 0);
        vb->tainted = in->tainted;
        fr_dcursor_append(out, vb);
 
index 6cb0ee4f92a42e25ea1c6cfe53bf0351b6da65be..ca04494bfb52cbba747ce10a78cd365c877a3590 100644 (file)
@@ -1,7 +1,4 @@
 /*
- * @copyright 1999, 2000, 2001, 2004, 2005, 2006 Free Software
- * Foundation, Inc.
- *
  * This program is left software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * @see RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>.
  *
  * @file src/lib/util/base64.c
- * @author Simon Josefsson.
+ *
+ * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
  */
 RCSID("$Id$")
 
 #include "base64.h"
 
 #include <freeradius-devel/util/strerror.h>
-
+#include <freeradius-devel/util/value.h>
 #define us(x) (uint8_t) x
 
-char const fr_base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+char const fr_base64_alphabet_encode[UINT8_MAX] = {
+       [0] = 'A',
+       [1] = 'B',
+       [2] = 'C',
+       [3] = 'D',
+       [4] = 'E',
+       [5] = 'F',
+       [6] = 'G',
+       [7] = 'H',
+       [8] = 'I',
+       [9] = 'J',
+       [10] = 'K',
+       [11] = 'L',
+       [12] = 'M',
+       [13] = 'N',
+       [14] = 'O',
+       [15] = 'P',
+       [16] = 'Q',
+       [17] = 'R',
+       [18] = 'S',
+       [19] = 'T',
+       [20] = 'U',
+       [21] = 'V',
+       [22] = 'W',
+       [23] = 'X',
+       [24] = 'Y',
+       [25] = 'Z',
+       [26] = 'a',
+       [27] = 'b',
+       [28] = 'c',
+       [29] = 'd',
+       [30] = 'e',
+       [31] = 'f',
+       [32] = 'g',
+       [33] = 'h',
+       [34] = 'i',
+       [35] = 'j',
+       [36] = 'k',
+       [37] = 'l',
+       [38] = 'm',
+       [39] = 'n',
+       [40] = 'o',
+       [41] = 'p',
+       [42] = 'q',
+       [43] = 'r',
+       [44] = 's',
+       [45] = 't',
+       [46] = 'u',
+       [47] = 'v',
+       [48] = 'w',
+       [49] = 'x',
+       [50] = 'y',
+       [51] = 'z',
+       [52] = '0',
+       [53] = '1',
+       [54] = '2',
+       [55] = '3',
+       [56] = '4',
+       [57] = '5',
+       [58] = '6',
+       [59] = '7',
+       [60] = '8',
+       [61] = '9',
+       [62] = '+',
+       [63] = '/'
+};
 
 uint8_t const fr_base64_alphabet_decode[UINT8_MAX] = {
        ['A'] = 0,
@@ -98,138 +161,188 @@ uint8_t const fr_base64_alphabet_decode[UINT8_MAX] = {
        ['8'] = 60,
        ['9'] = 61,
        ['+'] = 62,
-       ['.'] = 62,
        ['/'] = 63
 };
 
 /** Base 64 encode binary data
  *
- * Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+ * Base64 encode in bytes to base64, writing to out.
  *
- * @param[out] out     Where to write Base64 string.
- * @param[in] outlen   size of buffer including NULL byte.
- * @param[in] in       Data to encode.
- * @param[in] inlen    Length of data to encode.
+ * @param[out] out             Where to write Base64 string.
+ * @param[in] in               Data to encode.
+ * @param[in] add_padding      Add padding bytes.
+ * @param[in] alphabet         to use for encoding.
  * @return
  *     - Amount of data we wrote to the buffer.
- *     - -1 if output buffer was too small.
+ *     - <0 the number of bytes we would have needed in the ouput buffer.
  */
-size_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen)
+ssize_t fr_base64_encode_nstd(fr_sbuff_t *out, fr_dbuff_t *in,
+                             bool add_padding, char const alphabet[static UINT8_MAX])
 {
-       char *p = out;
-       size_t need = FR_BASE64_ENC_LENGTH(inlen) + 1;
+       fr_sbuff_t              our_out = FR_SBUFF_NO_ADVANCE(out);
+       fr_dbuff_t              our_in = FR_DBUFF_NO_ADVANCE(in);
 
-       if (outlen < need) {
-               fr_strerror_printf("Output buffer too small, exected %zu bytes, got %zu bytes", need, outlen);
-               *out = '\0';
-               return -1;
-       }
+       fr_strerror_const("Insufficient buffer space");
+
+       for (;;) {
+               uint8_t a, b, c;
+
+               switch (fr_dbuff_extend_lowat(NULL, &our_in, 3)) {
+               /*
+                *      Enough bytes for a 24bit quanta
+                */
+               default:
+                       a = *fr_dbuff_current(&our_in);
+                       b = *(fr_dbuff_current(&our_in) + 1);
+                       c = *(fr_dbuff_current(&our_in) + 2);
+                       FR_SBUFF_IN_CHAR_RETURN(&our_out,
+                                               alphabet[(a >> 2) & 0x3f],
+                                               alphabet[((a << 4) + (b >> 4)) & 0x3f],
+                                               alphabet[((b << 2) + (c >> 6)) & 0x3f],
+                                               alphabet[c & 0x3f]);
+                       fr_dbuff_advance(&our_in, 3);
+                       continue;
 
-       while (inlen) {
-               *p++ = fr_base64_str[(in[0] >> 2) & 0x3f];
-               *p++ = fr_base64_str[((in[0] << 4) + (--inlen ? in[1] >> 4 : 0)) & 0x3f];
-               *p++ = (inlen ? fr_base64_str[((in[1] << 2) + (--inlen ? in[2] >> 6 : 0)) & 0x3f] : '=');
-               *p++ = inlen ? fr_base64_str[in[2] & 0x3f] : '=';
+               case 2:
+                       a = *fr_dbuff_current(&our_in);
+                       b = *(fr_dbuff_current(&our_in) + 1);
+                       FR_SBUFF_IN_CHAR_RETURN(&our_out,
+                                               alphabet[(a >> 2) & 0x3f],
+                                               alphabet[((a << 4) + (b >> 4)) & 0x3f],
+                                               alphabet[(b << 2) & 0x3f]);
+                       fr_dbuff_advance(&our_in, 2);   /* Place at the end */
+                       if (add_padding) FR_SBUFF_IN_CHAR_RETURN(&our_out, '=');
+                       break;
 
-               if (inlen) inlen--;
-               if (inlen) in += 3;
+               case 1:
+                       a = *fr_dbuff_current(&our_in);
+                       FR_SBUFF_IN_CHAR_RETURN(&our_out,
+                                               alphabet[(a >> 2) & 0x3f],
+                                               alphabet[(a << 4) & 0x3f]);
+                       fr_dbuff_advance(&our_in, 1);   /* Place at the end */
+                       if (add_padding) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "==");
+                       break;
+
+               case 0:
+                       goto done;
+               }
+       done:
+               break;
        }
 
-       p[0] = '\0';
+       fr_strerror_clear();
 
-       return p - out;
+       fr_dbuff_set(in, &our_in);
+       return fr_sbuff_set(out, &our_out);
 }
 
 /* Decode base64 encoded input array.
  *
- * Decode base64 encoded input array IN of length INLEN to output array OUT that
- * can hold *OUTLEN bytes.  Return true if decoding was successful, i.e.
- * if the input was valid base64 data, -1 otherwise.
- *
- * If *OUTLEN is too small, as many bytes as possible will be written to OUT.
- * On return, *OUTLEN holds the length of decoded bytes in OUT.
- *
- * Note that as soon as any non-alphabet characters are encountered,
- * decoding is stopped and -1 is returned.
- *
- * This means that, when applicable, you must remove any line terminators
- * that is part of the data stream before calling this function.
- *
- * @param[out] out     Where to write the decoded data.
- * @param[in] outlen   The length of the output buffer.
- * @param[in] in       Base64 string to decode.
- * @param[in] inlen    length of Base64 string.
+ * @param[out] out             Where to write the decoded binary data.
+ * @param[in] in               Base64 string to decode.
+ * @param[in] expect_padding   Expect, and advanced past padding characters '=' at
+ *                             the end of the string.
+ * @param[in] no_trailing      Error out if we find non-base64 characters
+ *                             at the end of the string.
+ * @param[in] alphabet         to use for decoding.
  * @return
  *     - <= 0 on failure.  The offset where the decoding error occurred as a negative integer.
  *     - Length of decoded data.
  */
-ssize_t fr_base64_decode_nstd(uint8_t *out, size_t outlen, char const *in, size_t inlen, uint8_t const alphabet[static UINT8_MAX])
+ssize_t fr_base64_decode_nstd(fr_dbuff_t *out, fr_sbuff_t *in,
+                             bool expect_padding, bool no_trailing, uint8_t const alphabet[static UINT8_MAX])
 {
-       uint8_t         *out_p = out;
-       uint8_t         *out_end = out + outlen;
-       char const      *p = in, *q;
-       char const      *end = p + inlen;
+       fr_sbuff_t              our_in = FR_SBUFF_NO_ADVANCE(in);
+       fr_dbuff_t              our_out = FR_DBUFF_NO_ADVANCE(out);
+       fr_sbuff_marker_t       m_final;
+       uint8_t                 pad;
 
        /*
         *      Process complete 24bit quanta
         */
-       while ((end - p) >= 4) {
-               if (!fr_is_base64_nstd(p[0], alphabet) || !fr_is_base64_nstd(p[1], alphabet) ||
-                   !fr_is_base64_nstd(p[2], alphabet) || !fr_is_base64_nstd(p[3], alphabet)) break;
+       while (fr_sbuff_extend_lowat(NULL, &our_in, 4) >= 4) {
+               char *p = fr_sbuff_current(&our_in);
 
-               /*
-                *      Check we have enough bytes to write out
-                *      the 24bit quantum.
-                */
-               if ((out_end - out_p) <= 3) {
+               if (!fr_is_base64_nstd(p[0], alphabet) ||
+                   !fr_is_base64_nstd(p[1], alphabet) ||
+                   !fr_is_base64_nstd(p[2], alphabet) ||
+                   !fr_is_base64_nstd(p[3], alphabet)) break;
+
+               if (fr_dbuff_in_bytes(&our_out,
+                                     ((alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4)),
+                                     ((alphabet[us(p[1])] << 4) & 0xf0) | (alphabet[us(p[2])] >> 2),
+                                     ((alphabet[us(p[2])] << 6) & 0xc0) | alphabet[us(p[3])]) != 3) {
                oob:
-                       fr_strerror_printf("Output buffer too small, needed at least %zu bytes", outlen + 1);
-                       return p - end;
+                       fr_strerror_printf("Output buffer too small, needed at least %zu bytes",
+                                          fr_dbuff_used(&our_out) + 1);
+                       return -fr_sbuff_used(&our_in);
                }
 
-               *out_p++ = ((alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4));
-               *out_p++ = ((alphabet[us(p[1])] << 4) & 0xf0) | (alphabet[us(p[2])] >> 2);
-               *out_p++ = ((alphabet[us(p[2])] << 6) & 0xc0) | alphabet[us(p[3])];
-
-               p += 4; /* 32bit input -> 24bit output */
+               fr_sbuff_advance(&our_in, 4);
        }
 
-       q = p;
+       fr_sbuff_marker(&m_final, &our_in);
 
        /*
         *      Find the first non-base64 char
         */
-       while ((q < end) && fr_is_base64_nstd(*q, alphabet)) q++;
+       while (fr_sbuff_extend(&our_in) && fr_is_base64_nstd(*fr_sbuff_current(&our_in), alphabet)) {
+               fr_sbuff_advance(&our_in, 1);
+       }
 
-       switch (q - p) {
+       switch (fr_sbuff_behind(&m_final)) {
        case 0:         /* Final quantum is 24 bits */
+               pad = 0;
                break;
 
        case 2:         /* Final quantum is 8 bits */
-               if ((out_end - out_p) < 1) goto oob;
-               *out_p++ = ((alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4));
-               p += 2;
+       {
+               char *p = fr_sbuff_current(&m_final);
+
+               if (fr_dbuff_in_bytes(&our_out,
+                                     (alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4)) != 1) goto oob;
+               pad = 2;
+       }
                break;
 
        case 3:         /* Final quantum is 16 bits */
-               if ((out_end - out_p) < 2) goto oob;
-               *out_p++ = ((alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4));
-               *out_p++ = ((alphabet[us(p[1])] << 4) & 0xf0) | (alphabet[us(p[2])] >> 2);
-               p += 3;
+       {
+               char *p = fr_sbuff_current(&m_final);
+
+               if (fr_dbuff_in_bytes(&our_out,
+                                     ((alphabet[us(p[0])] << 2) | (alphabet[us(p[1])] >> 4)),
+                                     ((alphabet[us(p[1])] << 4) & 0xf0) | (alphabet[us(p[2])] >> 2)) != 2) goto oob;
+               pad = 1;
+       }
                break;
 
        default:
                fr_strerror_const("Invalid base64 padding data");
-               return p - end;
+               return -fr_sbuff_used(&our_in);
        }
 
-       while (p < end) {
-               if (*p != '=') {
-                       fr_strerror_printf("Found non-padding char '%c' at end of base64 string", *p);
-                       return p - end;
+       if (expect_padding) {
+               uint8_t i;
+               for (i = 0; i < pad; i++) {
+                       if (!fr_sbuff_extend(&our_in)) {
+                               fr_strerror_printf("Missing padding '=' at end of base64 string.  "
+                                                  "Expected %u padding char(s)", pad);
+                               return -fr_sbuff_used(&our_in);
+                       }
+                       if (!fr_sbuff_next_if_char(&our_in, '=')) {
+                               fr_strerror_printf("Found non-padding char '%c' at end of base64 string",
+                                                  *fr_sbuff_current(&our_in));
+                               return -fr_sbuff_used(&our_in);
+                       }
                }
-               p++;
        }
 
-       return out_p - out;
+       if (no_trailing && fr_sbuff_extend(&our_in)) {
+               fr_strerror_printf("Found trailing garbage '%c' at end of base64 string",
+                                  *fr_sbuff_current(&our_in));
+               return -fr_sbuff_used(&our_in);
+       }
+
+       fr_sbuff_set(in, &our_in);
+       return fr_dbuff_set(out, &our_out);
 }
index 290e1be048d727c81ed20e8115ae12ad6fa81f5a..0295f950018081a3267d394363f452e4a9fc98fc 100644 (file)
@@ -30,6 +30,8 @@ extern "C" {
 
 #include <freeradius-devel/build.h>
 #include <freeradius-devel/missing.h>
+#include <freeradius-devel/util/sbuff.h>
+#include <freeradius-devel/util/dbuff.h>
 
 #include <stdbool.h>
 #include <stddef.h>
@@ -41,14 +43,15 @@ extern "C" {
 #define FR_BASE64_ENC_LENGTH(_inlen) ((((_inlen) + 2) / 3) * 4)
 #define FR_BASE64_DEC_LENGTH(_inlen) ((3 * ((_inlen) / 4)) + 2)
 
-extern char const fr_base64_str[];
+extern char const fr_base64_alphabet_encode[UINT8_MAX];
 extern uint8_t const fr_base64_alphabet_decode[UINT8_MAX];
 
 /** Check if char is in Base64 alphabet
  *
  * Note that '=' is padding and not considered to be part of the alphabet.
  *
- * @param c char to check.
+ * @param[in] c char to check.
+ * @return
  *     - true if c is a character from the Base64 alphabet.
  *     - false if character is not in the Base64 alphabet.
  */
@@ -57,14 +60,23 @@ static inline bool fr_is_base64_nstd(char c, uint8_t const alphabet[static UINT8
        return (c == 'A') || (alphabet[(uint8_t)c] > 0);
 }
 
-#define fr_is_base64(_c) fr_is_base64_nstd(_c, fr_base64_alphabet_decode)
-
 size_t         fr_base64_encode(char * restrict out, size_t outlen, uint8_t const * restrict in, size_t inlen);
+#define                fr_is_base64(_c) fr_is_base64_nstd(_c, fr_base64_alphabet_decode)
+
+
+ssize_t                fr_base64_encode_nstd(fr_sbuff_t *out, fr_dbuff_t *in,
+                                     bool add_padding, char const alphabet[static UINT8_MAX])
+                                     CC_HINT(nonnull);
 
-#define                fr_base64_decode(_out, _outlen, _in, _inlen) fr_base64_decode_nstd(_out, _outlen, _in, _inlen, fr_base64_alphabet_decode)
-ssize_t                fr_base64_decode_nstd(uint8_t * restrict out, size_t outlen, char const * restrict in, size_t inlen, uint8_t const alphabet[static UINT8_MAX]);
+#define                fr_base64_encode(_out, _in, _add_padding) \
+               fr_base64_encode_nstd(_out, _in, _add_padding, fr_base64_alphabet_encode);
 
+ssize_t                fr_base64_decode_nstd(fr_dbuff_t *out, fr_sbuff_t *in,
+                                     bool expect_padding, bool no_trailing, uint8_t const alphabet[static UINT8_MAX])
+                                     CC_HINT(nonnull);
 
+#define                fr_base64_decode(_out, _in, _expect_padding, _no_trailing) \
+               fr_base64_decode_nstd(_out,  _in, _expect_padding, _no_trailing, fr_base64_alphabet_decode)
 
 #ifdef __cplusplus
 }
index 4d78fd818972b68e35f2df72df1c54ee9b923957..00117f7e8ad4f71bcde7e30e8e56686ea8c97ee4 100644 (file)
@@ -1183,11 +1183,12 @@ size_t _fr_sbuff_move_sbuff_to_marker(fr_sbuff_marker_t *out, fr_sbuff_t *in, si
 #define        FR_SBUFF_IN_CHAR_RETURN(_sbuff, ...) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, _sbuff, ((char []){ __VA_ARGS__ }), sizeof((char []){ __VA_ARGS__ }))
 
 ssize_t        fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str);
-#define fr_sbuff_in_strcpy_literal(_sbuff, _str) fr_sbuff_in_bstrncpy(_sbuff, _str, sizeof(_str) - 1)
 #define        FR_SBUFF_IN_STRCPY_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_strcpy, ##__VA_ARGS__)
 
 ssize_t        fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len);
 #define        FR_SBUFF_IN_BSTRNCPY_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, ##__VA_ARGS__)
+
+#define fr_sbuff_in_strcpy_literal(_sbuff, _str) fr_sbuff_in_bstrncpy(_sbuff, _str, sizeof(_str) - 1)
 #define        FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, _sbuff, _str, sizeof(_str) - 1)
 
 ssize_t        fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str);
index 838cbca516addfdc1829431f4ad93cf1531ba62c..22da5b554e5e96c0e57c79c022b9ffb737c96aa1 100644 (file)
@@ -535,8 +535,9 @@ static inline CC_HINT(nonnull) unlang_action_t pap_auth_pbkdf2_parse(rlm_rcode_t
         */
        } else {
                fr_strerror_clear();
-               slen = fr_base64_decode((uint8_t *)&iterations, sizeof(iterations), (char const *)p, q - p);
-               if (slen < 0) {
+               slen = fr_base64_decode(&FR_DBUFF_TMP((uint8_t *)&iterations, sizeof(iterations)),
+                                       &FR_SBUFF_IN((char const *)p, (char const *)q), false, false);
+               if (slen <= 0) {
                        RPEDEBUG("Failed decoding PBKDF2-Password iterations component (%.*s)", (int)(q - p), p);
                        goto finish;
                }
@@ -560,8 +561,9 @@ static inline CC_HINT(nonnull) unlang_action_t pap_auth_pbkdf2_parse(rlm_rcode_t
        }
 
        MEM(salt = talloc_array(request, uint8_t, FR_BASE64_DEC_LENGTH(q - p)));
-       slen = fr_base64_decode(salt, talloc_array_length(salt), (char const *) p, q - p);
-       if (slen < 0) {
+       slen = fr_base64_decode(&FR_DBUFF_TMP(salt, talloc_array_length(salt)),
+                               &FR_SBUFF_IN((char const *) p, (char const *)q), false, false);
+       if (slen <= 0) {
                RPEDEBUG("Failed decoding PBKDF2-Password salt component");
                goto finish;
        }
@@ -574,8 +576,9 @@ static inline CC_HINT(nonnull) unlang_action_t pap_auth_pbkdf2_parse(rlm_rcode_t
                goto finish;
        }
 
-       slen = fr_base64_decode(hash, sizeof(hash), (char const *)p, end - p);
-       if (slen < 0) {
+       slen = fr_base64_decode(&FR_DBUFF_TMP(hash, sizeof(hash)),
+                               &FR_SBUFF_IN((char const *)p, (char const *)end), false, false);
+       if (slen <= 0) {
                RPEDEBUG("Failed decoding PBKDF2-Password hash component");
                goto finish;
        }
index 43c63d42c4f5154d717cb68d10378993c6255c26..e2a7e36bc3f2de53caeb4f26c90d71305717e1ae 100644 (file)
@@ -107,4 +107,20 @@ if (&Tmp-Octets-1 != 0x008000000000000000000000000039383739) {
        test_fail
 }
 
+# Regression tests
+update request {
+       &Tmp-Octets-0 := %{base64decode:5RNqNl8iYLbkCc7JhR8as4TtDDCX6otuuWtcja8rITUyx9zrnHSe9tTHGmKK}
+}
+
+if (&Tmp-Octets-0 != 0xe5136a365f2260b6e409cec9851f1ab384ed0c3097ea8b6eb96b5c8daf2b213532c7dceb9c749ef6d4c71a628a) {
+       test_fail
+}
+
+update request {
+       &Tmp-Octets-0 := "%{base64decode:eHfXPKZ+2iv9cnMV1MOmE/moYYA1Uk5xTmw4aVlMYmtDYzdKaFI4YXM0VHRERENYNm90dXVXdGNqYThySVRVeXg5enJuSFNlOXRUSEdtS0s=}"
+}
+
+if (&Tmp-Octets-0 != 0x7877d73ca67eda2bfd727315d4c3a613f9a8618035524e714e6c3869594c626b4363374a685238617334547444444358366f7475755774636a6138724954557978397a726e48536539745448476d4b4b) {
+       test_fail
+}
 success