• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 /* Base64 encoding/decoding */
24 
25 #include "curl_setup.h"
26 
27 #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
28   !defined(CURL_DISABLE_LDAP) || \
29   !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
30 
31 #include "urldata.h" /* for the Curl_easy definition */
32 #include "warnless.h"
33 #include "curl_base64.h"
34 #include "non-ascii.h"
35 
36 /* The last 3 #include files should be in this order */
37 #include "curl_printf.h"
38 #include "curl_memory.h"
39 #include "memdebug.h"
40 
41 /* ---- Base64 Encoding/Decoding Table --- */
42 static const char base64[]=
43   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44 
45 /* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648
46    section 5 */
47 static const char base64url[]=
48   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
49 
decodeQuantum(unsigned char * dest,const char * src)50 static size_t decodeQuantum(unsigned char *dest, const char *src)
51 {
52   size_t padding = 0;
53   const char *s, *p;
54   unsigned long i, x = 0;
55 
56   for(i = 0, s = src; i < 4; i++, s++) {
57     if(*s == '=') {
58       x = (x << 6);
59       padding++;
60     }
61     else {
62       unsigned long v = 0;
63       p = base64;
64 
65       while(*p && (*p != *s)) {
66         v++;
67         p++;
68       }
69 
70       if(*p == *s)
71         x = (x << 6) + v;
72       else
73         return 0;
74     }
75   }
76 
77   if(padding < 1)
78     dest[2] = curlx_ultouc(x & 0xFFUL);
79 
80   x >>= 8;
81   if(padding < 2)
82     dest[1] = curlx_ultouc(x & 0xFFUL);
83 
84   x >>= 8;
85   dest[0] = curlx_ultouc(x & 0xFFUL);
86 
87   return 3 - padding;
88 }
89 
90 /*
91  * Curl_base64_decode()
92  *
93  * Given a base64 NUL-terminated string at src, decode it and return a
94  * pointer in *outptr to a newly allocated memory area holding decoded
95  * data. Size of decoded data is returned in variable pointed by outlen.
96  *
97  * Returns CURLE_OK on success, otherwise specific error code. Function
98  * output shall not be considered valid unless CURLE_OK is returned.
99  *
100  * When decoded data length is 0, returns NULL in *outptr.
101  *
102  * @unittest: 1302
103  */
Curl_base64_decode(const char * src,unsigned char ** outptr,size_t * outlen)104 CURLcode Curl_base64_decode(const char *src,
105                             unsigned char **outptr, size_t *outlen)
106 {
107   size_t srclen = 0;
108   size_t length = 0;
109   size_t padding = 0;
110   size_t i;
111   size_t numQuantums;
112   size_t rawlen = 0;
113   unsigned char *pos;
114   unsigned char *newstr;
115 
116   *outptr = NULL;
117   *outlen = 0;
118   srclen = strlen(src);
119 
120   /* Check the length of the input string is valid */
121   if(!srclen || srclen % 4)
122     return CURLE_BAD_CONTENT_ENCODING;
123 
124   /* Find the position of any = padding characters */
125   while((src[length] != '=') && src[length])
126     length++;
127 
128   /* A maximum of two = padding characters is allowed */
129   if(src[length] == '=') {
130     padding++;
131     if(src[length + 1] == '=')
132       padding++;
133   }
134 
135   /* Check the = padding characters weren't part way through the input */
136   if(length + padding != srclen)
137     return CURLE_BAD_CONTENT_ENCODING;
138 
139   /* Calculate the number of quantums */
140   numQuantums = srclen / 4;
141 
142   /* Calculate the size of the decoded string */
143   rawlen = (numQuantums * 3) - padding;
144 
145   /* Allocate our buffer including room for a zero terminator */
146   newstr = malloc(rawlen + 1);
147   if(!newstr)
148     return CURLE_OUT_OF_MEMORY;
149 
150   pos = newstr;
151 
152   /* Decode the quantums */
153   for(i = 0; i < numQuantums; i++) {
154     size_t result = decodeQuantum(pos, src);
155     if(!result) {
156       free(newstr);
157 
158       return CURLE_BAD_CONTENT_ENCODING;
159     }
160 
161     pos += result;
162     src += 4;
163   }
164 
165   /* Zero terminate */
166   *pos = '\0';
167 
168   /* Return the decoded data */
169   *outptr = newstr;
170   *outlen = rawlen;
171 
172   return CURLE_OK;
173 }
174 
base64_encode(const char * table64,struct Curl_easy * data,const char * inputbuff,size_t insize,char ** outptr,size_t * outlen)175 static CURLcode base64_encode(const char *table64,
176                               struct Curl_easy *data,
177                               const char *inputbuff, size_t insize,
178                               char **outptr, size_t *outlen)
179 {
180   CURLcode result;
181   unsigned char ibuf[3];
182   unsigned char obuf[4];
183   int i;
184   int inputparts;
185   char *output;
186   char *base64data;
187   char *convbuf = NULL;
188 
189   const char *indata = inputbuff;
190 
191   *outptr = NULL;
192   *outlen = 0;
193 
194   if(!insize)
195     insize = strlen(indata);
196 
197 #if SIZEOF_SIZE_T == 4
198   if(insize > UINT_MAX/4)
199     return CURLE_OUT_OF_MEMORY;
200 #endif
201 
202   base64data = output = malloc(insize * 4 / 3 + 4);
203   if(!output)
204     return CURLE_OUT_OF_MEMORY;
205 
206   /*
207    * The base64 data needs to be created using the network encoding
208    * not the host encoding.  And we can't change the actual input
209    * so we copy it to a buffer, translate it, and use that instead.
210    */
211   result = Curl_convert_clone(data, indata, insize, &convbuf);
212   if(result) {
213     free(output);
214     return result;
215   }
216 
217   if(convbuf)
218     indata = (char *)convbuf;
219 
220   while(insize > 0) {
221     for(i = inputparts = 0; i < 3; i++) {
222       if(insize > 0) {
223         inputparts++;
224         ibuf[i] = (unsigned char) *indata;
225         indata++;
226         insize--;
227       }
228       else
229         ibuf[i] = 0;
230     }
231 
232     obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
233     obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
234                                ((ibuf[1] & 0xF0) >> 4));
235     obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
236                                ((ibuf[2] & 0xC0) >> 6));
237     obuf[3] = (unsigned char)   (ibuf[2] & 0x3F);
238 
239     switch(inputparts) {
240     case 1: /* only one byte read */
241       msnprintf(output, 5, "%c%c==",
242                 table64[obuf[0]],
243                 table64[obuf[1]]);
244       break;
245 
246     case 2: /* two bytes read */
247       msnprintf(output, 5, "%c%c%c=",
248                 table64[obuf[0]],
249                 table64[obuf[1]],
250                 table64[obuf[2]]);
251       break;
252 
253     default:
254       msnprintf(output, 5, "%c%c%c%c",
255                 table64[obuf[0]],
256                 table64[obuf[1]],
257                 table64[obuf[2]],
258                 table64[obuf[3]]);
259       break;
260     }
261     output += 4;
262   }
263 
264   /* Zero terminate */
265   *output = '\0';
266 
267   /* Return the pointer to the new data (allocated memory) */
268   *outptr = base64data;
269 
270   free(convbuf);
271 
272   /* Return the length of the new data */
273   *outlen = strlen(base64data);
274 
275   return CURLE_OK;
276 }
277 
278 /*
279  * Curl_base64_encode()
280  *
281  * Given a pointer to an input buffer and an input size, encode it and
282  * return a pointer in *outptr to a newly allocated memory area holding
283  * encoded data. Size of encoded data is returned in variable pointed by
284  * outlen.
285  *
286  * Input length of 0 indicates input buffer holds a NUL-terminated string.
287  *
288  * Returns CURLE_OK on success, otherwise specific error code. Function
289  * output shall not be considered valid unless CURLE_OK is returned.
290  *
291  * When encoded data length is 0, returns NULL in *outptr.
292  *
293  * @unittest: 1302
294  */
Curl_base64_encode(struct Curl_easy * data,const char * inputbuff,size_t insize,char ** outptr,size_t * outlen)295 CURLcode Curl_base64_encode(struct Curl_easy *data,
296                             const char *inputbuff, size_t insize,
297                             char **outptr, size_t *outlen)
298 {
299   return base64_encode(base64, data, inputbuff, insize, outptr, outlen);
300 }
301 
302 /*
303  * Curl_base64url_encode()
304  *
305  * Given a pointer to an input buffer and an input size, encode it and
306  * return a pointer in *outptr to a newly allocated memory area holding
307  * encoded data. Size of encoded data is returned in variable pointed by
308  * outlen.
309  *
310  * Input length of 0 indicates input buffer holds a NUL-terminated string.
311  *
312  * Returns CURLE_OK on success, otherwise specific error code. Function
313  * output shall not be considered valid unless CURLE_OK is returned.
314  *
315  * When encoded data length is 0, returns NULL in *outptr.
316  *
317  * @unittest: 1302
318  */
Curl_base64url_encode(struct Curl_easy * data,const char * inputbuff,size_t insize,char ** outptr,size_t * outlen)319 CURLcode Curl_base64url_encode(struct Curl_easy *data,
320                                const char *inputbuff, size_t insize,
321                                char **outptr, size_t *outlen)
322 {
323   return base64_encode(base64url, data, inputbuff, insize, outptr, outlen);
324 }
325 
326 #endif /* no users so disabled */
327