960a1ca3ad82de75373003cf10aa3d3222dcfaf6
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / base64.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, 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.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_SMTP) || \
30   !defined(CURL_DISABLE_POP3) || \
31   !defined(CURL_DISABLE_IMAP) || \
32   !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
33
34 #include "urldata.h" /* for the Curl_easy definition */
35 #include "warnless.h"
36 #include "curl_base64.h"
37
38 /* The last 3 #include files should be in this order */
39 #include "curl_printf.h"
40 #include "curl_memory.h"
41 #include "memdebug.h"
42
43 /* ---- Base64 Encoding/Decoding Table --- */
44 static const char base64[]=
45   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
46
47 /* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648
48    section 5 */
49 static const char base64url[]=
50   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
51
52 static size_t decodeQuantum(unsigned char *dest, const char *src)
53 {
54   size_t padding = 0;
55   const char *s, *p;
56   unsigned long i, x = 0;
57
58   for(i = 0, s = src; i < 4; i++, s++) {
59     if(*s == '=') {
60       x = (x << 6);
61       padding++;
62     }
63     else {
64       unsigned long v = 0;
65       p = base64;
66
67       while(*p && (*p != *s)) {
68         v++;
69         p++;
70       }
71
72       if(*p == *s)
73         x = (x << 6) + v;
74       else
75         return 0;
76     }
77   }
78
79   if(padding < 1)
80     dest[2] = curlx_ultouc(x & 0xFFUL);
81
82   x >>= 8;
83   if(padding < 2)
84     dest[1] = curlx_ultouc(x & 0xFFUL);
85
86   x >>= 8;
87   dest[0] = curlx_ultouc(x & 0xFFUL);
88
89   return 3 - padding;
90 }
91
92 /*
93  * Curl_base64_decode()
94  *
95  * Given a base64 NUL-terminated string at src, decode it and return a
96  * pointer in *outptr to a newly allocated memory area holding decoded
97  * data. Size of decoded data is returned in variable pointed by outlen.
98  *
99  * Returns CURLE_OK on success, otherwise specific error code. Function
100  * output shall not be considered valid unless CURLE_OK is returned.
101  *
102  * When decoded data length is 0, returns NULL in *outptr.
103  *
104  * @unittest: 1302
105  */
106 CURLcode Curl_base64_decode(const char *src,
107                             unsigned char **outptr, size_t *outlen)
108 {
109   size_t srclen = 0;
110   size_t length = 0;
111   size_t padding = 0;
112   size_t i;
113   size_t numQuantums;
114   size_t rawlen = 0;
115   unsigned char *pos;
116   unsigned char *newstr;
117
118   *outptr = NULL;
119   *outlen = 0;
120   srclen = strlen(src);
121
122   /* Check the length of the input string is valid */
123   if(!srclen || srclen % 4)
124     return CURLE_BAD_CONTENT_ENCODING;
125
126   /* Find the position of any = padding characters */
127   while((src[length] != '=') && src[length])
128     length++;
129
130   /* A maximum of two = padding characters is allowed */
131   if(src[length] == '=') {
132     padding++;
133     if(src[length + 1] == '=')
134       padding++;
135   }
136
137   /* Check the = padding characters weren't part way through the input */
138   if(length + padding != srclen)
139     return CURLE_BAD_CONTENT_ENCODING;
140
141   /* Calculate the number of quantums */
142   numQuantums = srclen / 4;
143
144   /* Calculate the size of the decoded string */
145   rawlen = (numQuantums * 3) - padding;
146
147   /* Allocate our buffer including room for a zero terminator */
148   newstr = malloc(rawlen + 1);
149   if(!newstr)
150     return CURLE_OUT_OF_MEMORY;
151
152   pos = newstr;
153
154   /* Decode the quantums */
155   for(i = 0; i < numQuantums; i++) {
156     size_t result = decodeQuantum(pos, src);
157     if(!result) {
158       free(newstr);
159
160       return CURLE_BAD_CONTENT_ENCODING;
161     }
162
163     pos += result;
164     src += 4;
165   }
166
167   /* Zero terminate */
168   *pos = '\0';
169
170   /* Return the decoded data */
171   *outptr = newstr;
172   *outlen = rawlen;
173
174   return CURLE_OK;
175 }
176
177 static CURLcode base64_encode(const char *table64,
178                               const char *inputbuff, size_t insize,
179                               char **outptr, size_t *outlen)
180 {
181   unsigned char ibuf[3];
182   unsigned char obuf[4];
183   int i;
184   int inputparts;
185   char *output;
186   char *base64data;
187   const char *indata = inputbuff;
188
189   *outptr = NULL;
190   *outlen = 0;
191
192   if(!insize)
193     insize = strlen(indata);
194
195 #if SIZEOF_SIZE_T == 4
196   if(insize > UINT_MAX/4)
197     return CURLE_OUT_OF_MEMORY;
198 #endif
199
200   base64data = output = malloc(insize * 4 / 3 + 4);
201   if(!output)
202     return CURLE_OUT_OF_MEMORY;
203
204   while(insize > 0) {
205     for(i = inputparts = 0; i < 3; i++) {
206       if(insize > 0) {
207         inputparts++;
208         ibuf[i] = (unsigned char) *indata;
209         indata++;
210         insize--;
211       }
212       else
213         ibuf[i] = 0;
214     }
215
216     obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
217     obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
218                                ((ibuf[1] & 0xF0) >> 4));
219     obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
220                                ((ibuf[2] & 0xC0) >> 6));
221     obuf[3] = (unsigned char)   (ibuf[2] & 0x3F);
222
223     switch(inputparts) {
224     case 1: /* only one byte read */
225       msnprintf(output, 5, "%c%c==",
226                 table64[obuf[0]],
227                 table64[obuf[1]]);
228       break;
229
230     case 2: /* two bytes read */
231       msnprintf(output, 5, "%c%c%c=",
232                 table64[obuf[0]],
233                 table64[obuf[1]],
234                 table64[obuf[2]]);
235       break;
236
237     default:
238       msnprintf(output, 5, "%c%c%c%c",
239                 table64[obuf[0]],
240                 table64[obuf[1]],
241                 table64[obuf[2]],
242                 table64[obuf[3]]);
243       break;
244     }
245     output += 4;
246   }
247
248   /* Zero terminate */
249   *output = '\0';
250
251   /* Return the pointer to the new data (allocated memory) */
252   *outptr = base64data;
253
254   /* Return the length of the new data */
255   *outlen = output - base64data;
256
257   return CURLE_OK;
258 }
259
260 /*
261  * Curl_base64_encode()
262  *
263  * Given a pointer to an input buffer and an input size, encode it and
264  * return a pointer in *outptr to a newly allocated memory area holding
265  * encoded data. Size of encoded data is returned in variable pointed by
266  * outlen.
267  *
268  * Input length of 0 indicates input buffer holds a NUL-terminated string.
269  *
270  * Returns CURLE_OK on success, otherwise specific error code. Function
271  * output shall not be considered valid unless CURLE_OK is returned.
272  *
273  * When encoded data length is 0, returns NULL in *outptr.
274  *
275  * @unittest: 1302
276  */
277 CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
278                             char **outptr, size_t *outlen)
279 {
280   return base64_encode(base64, inputbuff, insize, outptr, outlen);
281 }
282
283 /*
284  * Curl_base64url_encode()
285  *
286  * Given a pointer to an input buffer and an input size, encode it and
287  * return a pointer in *outptr to a newly allocated memory area holding
288  * encoded data. Size of encoded data is returned in variable pointed by
289  * outlen.
290  *
291  * Input length of 0 indicates input buffer holds a NUL-terminated string.
292  *
293  * Returns CURLE_OK on success, otherwise specific error code. Function
294  * output shall not be considered valid unless CURLE_OK is returned.
295  *
296  * When encoded data length is 0, returns NULL in *outptr.
297  *
298  * @unittest: 1302
299  */
300 CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
301                                char **outptr, size_t *outlen)
302 {
303   return base64_encode(base64url, inputbuff, insize, outptr, outlen);
304 }
305
306 #endif /* no users so disabled */