varnish-cache/lib/libvmod_blob/base64.c
1
/*-
2
 * Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Authors: Nils Goroll <nils.goroll@uplex.de>
6
 *          Geoffrey Simmons <geoffrey.simmons@uplex.de>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are met:
10
 * 1. Redistributions of source code must retain the above copyright notice,
11
 *    this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 *
27
 */
28
29
#include "config.h"
30
#include <errno.h>
31
32
#include "base64.h"
33
34
#include "vdef.h"
35
#include "vrt.h"
36
#include "vas.h"
37
38
#define base64_l(l)             (((l) << 2) / 3)
39
40
size_t
41 420
base64nopad_encode_l(size_t l)
42
{
43 420
        return base64_l(l) + 4;
44
}
45
46
size_t
47 1176
base64_encode_l(size_t l)
48
{
49 1176
        return (((base64_l(l)) + 3) & ~3) + 1;
50
}
51
52
size_t
53 744
base64_decode_l(size_t l)
54
{
55 744
        return ((l) * 3) >> 2;
56
}
57
58
static inline int
59 30444
decode(char *restrict *restrict dest, const char *restrict const buf,
60
       const size_t buflen, unsigned u, const int n)
61
{
62
        char *d;
63
64 30444
        if (n <= 1) {
65 0
                errno = EINVAL;
66 0
                return -1;
67
        }
68 30444
        d = *dest;
69 120756
        for (int i = 0; i < n - 1; i++) {
70 90324
                if (d == buf + buflen) {
71 12
                        errno = ENOMEM;
72 12
                        return -1;
73
                }
74 90312
                *d++ = (u >> 16) & 0xff;
75 90312
                u <<= 8;
76
        }
77 30432
        *dest += d - *dest;
78 30432
        return 1;
79
}
80
81
ssize_t
82 1356
base64_encode(const enum encoding enc, const enum case_e kase,
83
              char *restrict const buf, const size_t buflen,
84
              const char *restrict const inbuf, const size_t inlength)
85
{
86 1356
        const struct b64_alphabet *alpha = &b64_alphabet[enc];
87 1356
        char *p = buf;
88 1356
        const uint8_t *in = (const uint8_t *)inbuf;
89 1356
        const uint8_t * const end = in + inlength;
90
91
        (void) kase;
92 1356
        AN(buf);
93 1356
        AN(alpha);
94 1356
        if (in == NULL || inlength == 0)
95 48
                return 0;
96
97 1644
        if ((enc == BASE64URLNOPAD &&
98 1644
             buflen < base64nopad_encode_l(inlength)) ||
99 972
            (enc != BASE64URLNOPAD &&
100 972
             buflen < base64_encode_l(inlength))) {
101 12
                errno = ENOMEM;
102 12
                return -1;
103
        }
104
105 42780
        while (end - in >= 3) {
106 40188
                *p++ = alpha->b64[(in[0] >> 2) & 0x3f];
107 40188
                *p++ = alpha->b64[((in[0] << 4) | (in[1] >> 4)) & 0x3f];
108 40188
                *p++ = alpha->b64[((in[1] << 2) | (in[2] >> 6)) & 0x3f];
109 40188
                *p++ = alpha->b64[in[2] & 0x3f];
110 40188
                in += 3;
111
        }
112 1296
        if (end - in > 0) {
113 1104
                *p++ = alpha->b64[(in[0] >> 2) & 0x3f];
114 1104
                if (end - in == 1) {
115 864
                        *p++ = alpha->b64[(in[0] << 4) & 0x3f];
116 864
                        if (alpha->padding) {
117 636
                                *p++ = alpha->padding;
118 636
                                *p++ = alpha->padding;
119
                        }
120
                }
121
                else {
122 240
                        *p++ = alpha->b64[((in[0] << 4) | (in[1] >> 4)) & 0x3f];
123 240
                        *p++ = alpha->b64[(in[1] << 2) & 0x3f];
124 240
                        if (alpha->padding) {
125 132
                                *p++ = alpha->padding;
126
                        }
127
                }
128
        }
129 1296
        assert(p >= buf && p - buf <= buflen);
130 1296
        return p - buf;
131
}
132
133
ssize_t
134 1500
base64_decode(const enum encoding dec, char *restrict const buf,
135
              const size_t buflen, ssize_t inlen,
136
              const char *const p, va_list ap)
137
{
138 1500
        const struct b64_alphabet *alpha = &b64_alphabet[dec];
139 1500
        char *dest = buf;
140 1500
        unsigned u = 0, term = 0;
141 1500
        int n = 0;
142 1500
        size_t len = SIZE_MAX;
143
144 1500
        AN(buf);
145 1500
        AN(alpha);
146
147 1500
        if (inlen >= 0)
148 564
                len = inlen;
149
150 4908
        for (const char *s = p; len > 0 && s != vrt_magic_string_end;
151 1908
             s = va_arg(ap, const char *)) {
152 2172
                if (s == NULL)
153 72
                        continue;
154 2100
                if (*s && term) {
155 0
                        errno = EINVAL;
156 0
                        return -1;
157
                }
158 35112
                while (*s && len) {
159 182772
                        while (n < 4) {
160 121968
                                char b = alpha->i64[(unsigned) *s++];
161 121968
                                u <<= 6;
162 121968
                                if (b == ILL) {
163 252
                                        errno = EINVAL;
164 252
                                        return -1;
165
                                }
166 121716
                                n++;
167 121716
                                if (b == PAD) {
168 696
                                        term++;
169 696
                                        continue;
170
                                }
171 121020
                                u |= (unsigned) b;
172 121020
                                if (--len == 0)
173 360
                                        break;
174 120660
                                if (!*s)
175 936
                                        break;
176
                        }
177 30924
                        if (n == 4) {
178 30276
                                if (decode(&dest, buf, buflen, u, n-term) < 0)
179 12
                                        return -1;
180 30264
                                n = 0;
181
                        }
182
                }
183
        }
184 1236
        if (n) {
185 168
                if (!alpha->padding)
186 156
                        u <<= (6 * (4 - n));
187 168
                if (decode(&dest, buf, buflen, u, n-term) < 0)
188 0
                        return -1;
189
        }
190
191 1236
        return dest - buf;
192
}