Annotation of embedaddon/curl/lib/base64.c, revision 1.1.1.1

1.1       misho       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: 
                     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:  */
                    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: 
                    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:  */
                    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:  */
                    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 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>