File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / base64.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>