The function

int
b64_pton(char const *src, u_char *target, size_t targsize);

in src/lib/libc/net/base64.c has a small bug with no consequences in
the rest of the tree.

By design, b64_pton() can be called with a NULL pointer as `target', in
which case it calculates the number of bytes encoded in the Base64
string `src'.  However, in presence of padding, the function doesn't
fully check whether the string is a valid Base64 string: It only counts
the number of padding characters and checks whether they occur in the
correct positions.

For instance, `b64_pton("//==", NULL, 1);' returns 1, even though "//=="
isn't actually a valid Base64 string.
The call `b64_pton("//==", target, 1);' correctly rejects the string
and returns -1.

Similarly, `b64_pton("///=", NULL, 2);' shouldn't return 2, but -1.


To fix this, I suggest to move the calculation of `nextbyte' in
states 1 and 2 out of the conditional `if (target)' and to use
`nextbyte' as a flag whether padding is allowed or not -- the current
character is allowed to be a padding character if and only if
(nextbyte == 0 && (state == 2 || state == 3)).


A nice side effect is that

if (target && tarindex < targsize && target[tarindex] != 0)

at the end of the routine can be replaced by the much simpler

if (nextbyte)

It makes more sense to me to bail out right away rather than deferring
this check to the end of the fiddling with the padding characters.


Index: base64.c
===================================================================
RCS file: /cvs/src/lib/libc/net/base64.c,v
retrieving revision 1.7
diff -u -p -r1.7 base64.c
--- base64.c    31 Dec 2013 02:32:56 -0000      1.7
+++ base64.c    16 Sep 2014 12:51:34 -0000
@@ -197,6 +197,7 @@ b64_pton(src, target, targsize)
        u_char nextbyte;
        char *pos;
 
+       nextbyte = 0;
        state = 0;
        tarindex = 0;
 
@@ -204,8 +205,17 @@ b64_pton(src, target, targsize)
                if (isspace(ch))        /* Skip whitespace anywhere. */
                        continue;
 
-               if (ch == Pad64)
+               if (ch == Pad64) {
+                       if (nextbyte)
+                               /*
+                                * We're in state 2 or 3 and the last character
+                                * slopped over the last byte boundary into the
+                                * padded byte.
+                                */
+                               return (-1);
+
                        break;
+               }
 
                pos = strchr(Base64, ch);
                if (pos == 0)           /* A non-base64 character. */
@@ -221,11 +231,11 @@ b64_pton(src, target, targsize)
                        state = 1;
                        break;
                case 1:
+                       nextbyte = ((pos - Base64) & 0x0f) << 4;
                        if (target) {
                                if (tarindex >= targsize)
                                        return (-1);
                                target[tarindex]   |=  (pos - Base64) >> 4;
-                               nextbyte = ((pos - Base64) & 0x0f) << 4;
                                if (tarindex + 1 < targsize)
                                        target[tarindex+1] = nextbyte;
                                else if (nextbyte)
@@ -235,11 +245,11 @@ b64_pton(src, target, targsize)
                        state = 2;
                        break;
                case 2:
+                       nextbyte = ((pos - Base64) & 0x03) << 6;
                        if (target) {
                                if (tarindex >= targsize)
                                        return (-1);
                                target[tarindex]   |=  (pos - Base64) >> 2;
-                               nextbyte = ((pos - Base64) & 0x03) << 6;
                                if (tarindex + 1 < targsize)
                                        target[tarindex+1] = nextbyte;
                                else if (nextbyte)
@@ -249,6 +259,7 @@ b64_pton(src, target, targsize)
                        state = 3;
                        break;
                case 3:
+                       nextbyte = 0;
                        if (target) {
                                if (tarindex >= targsize)
                                        return (-1);
@@ -292,16 +303,6 @@ b64_pton(src, target, targsize)
                        for (; ch != '\0'; ch = (unsigned char)*src++)
                                if (!isspace(ch))
                                        return (-1);
-
-                       /*
-                        * Now make sure for cases 2 and 3 that the "extra"
-                        * bits that slopped past the last full byte were
-                        * zeros.  If we don't check them, they become a
-                        * subliminal channel.
-                        */
-                       if (target && tarindex < targsize &&
-                           target[tarindex] != 0)
-                               return (-1);
                }
        } else {
                /*

Reply via email to