113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci/* Base64 encoding/decoding */ 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#include "curl_setup.h" 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \ 3013498266Sopenharmony_ci !defined(CURL_DISABLE_LDAP) || \ 3113498266Sopenharmony_ci !defined(CURL_DISABLE_SMTP) || \ 3213498266Sopenharmony_ci !defined(CURL_DISABLE_POP3) || \ 3313498266Sopenharmony_ci !defined(CURL_DISABLE_IMAP) || \ 3413498266Sopenharmony_ci !defined(CURL_DISABLE_DIGEST_AUTH) || \ 3513498266Sopenharmony_ci !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL) 3613498266Sopenharmony_ci#include "curl/curl.h" 3713498266Sopenharmony_ci#include "warnless.h" 3813498266Sopenharmony_ci#include "curl_base64.h" 3913498266Sopenharmony_ci 4013498266Sopenharmony_ci/* The last 2 #include files should be in this order */ 4113498266Sopenharmony_ci#ifdef BUILDING_LIBCURL 4213498266Sopenharmony_ci#include "curl_memory.h" 4313498266Sopenharmony_ci#endif 4413498266Sopenharmony_ci#include "memdebug.h" 4513498266Sopenharmony_ci 4613498266Sopenharmony_ci/* ---- Base64 Encoding/Decoding Table --- */ 4713498266Sopenharmony_ci/* Padding character string starts at offset 64. */ 4813498266Sopenharmony_cistatic const char base64encdec[]= 4913498266Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648 5213498266Sopenharmony_ci section 5 */ 5313498266Sopenharmony_cistatic const char base64url[]= 5413498266Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 5513498266Sopenharmony_ci 5613498266Sopenharmony_cistatic const unsigned char decodetable[] = 5713498266Sopenharmony_ci{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 5813498266Sopenharmony_ci 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 5913498266Sopenharmony_ci 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 6013498266Sopenharmony_ci 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 6113498266Sopenharmony_ci 48, 49, 50, 51 }; 6213498266Sopenharmony_ci/* 6313498266Sopenharmony_ci * Curl_base64_decode() 6413498266Sopenharmony_ci * 6513498266Sopenharmony_ci * Given a base64 NUL-terminated string at src, decode it and return a 6613498266Sopenharmony_ci * pointer in *outptr to a newly allocated memory area holding decoded 6713498266Sopenharmony_ci * data. Size of decoded data is returned in variable pointed by outlen. 6813498266Sopenharmony_ci * 6913498266Sopenharmony_ci * Returns CURLE_OK on success, otherwise specific error code. Function 7013498266Sopenharmony_ci * output shall not be considered valid unless CURLE_OK is returned. 7113498266Sopenharmony_ci * 7213498266Sopenharmony_ci * When decoded data length is 0, returns NULL in *outptr. 7313498266Sopenharmony_ci * 7413498266Sopenharmony_ci * @unittest: 1302 7513498266Sopenharmony_ci */ 7613498266Sopenharmony_ciCURLcode Curl_base64_decode(const char *src, 7713498266Sopenharmony_ci unsigned char **outptr, size_t *outlen) 7813498266Sopenharmony_ci{ 7913498266Sopenharmony_ci size_t srclen = 0; 8013498266Sopenharmony_ci size_t padding = 0; 8113498266Sopenharmony_ci size_t i; 8213498266Sopenharmony_ci size_t numQuantums; 8313498266Sopenharmony_ci size_t fullQuantums; 8413498266Sopenharmony_ci size_t rawlen = 0; 8513498266Sopenharmony_ci unsigned char *pos; 8613498266Sopenharmony_ci unsigned char *newstr; 8713498266Sopenharmony_ci unsigned char lookup[256]; 8813498266Sopenharmony_ci 8913498266Sopenharmony_ci *outptr = NULL; 9013498266Sopenharmony_ci *outlen = 0; 9113498266Sopenharmony_ci srclen = strlen(src); 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci /* Check the length of the input string is valid */ 9413498266Sopenharmony_ci if(!srclen || srclen % 4) 9513498266Sopenharmony_ci return CURLE_BAD_CONTENT_ENCODING; 9613498266Sopenharmony_ci 9713498266Sopenharmony_ci /* srclen is at least 4 here */ 9813498266Sopenharmony_ci while(src[srclen - 1 - padding] == '=') { 9913498266Sopenharmony_ci /* count padding characters */ 10013498266Sopenharmony_ci padding++; 10113498266Sopenharmony_ci /* A maximum of two = padding characters is allowed */ 10213498266Sopenharmony_ci if(padding > 2) 10313498266Sopenharmony_ci return CURLE_BAD_CONTENT_ENCODING; 10413498266Sopenharmony_ci } 10513498266Sopenharmony_ci 10613498266Sopenharmony_ci /* Calculate the number of quantums */ 10713498266Sopenharmony_ci numQuantums = srclen / 4; 10813498266Sopenharmony_ci fullQuantums = numQuantums - (padding ? 1 : 0); 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci /* Calculate the size of the decoded string */ 11113498266Sopenharmony_ci rawlen = (numQuantums * 3) - padding; 11213498266Sopenharmony_ci 11313498266Sopenharmony_ci /* Allocate our buffer including room for a null-terminator */ 11413498266Sopenharmony_ci newstr = malloc(rawlen + 1); 11513498266Sopenharmony_ci if(!newstr) 11613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 11713498266Sopenharmony_ci 11813498266Sopenharmony_ci pos = newstr; 11913498266Sopenharmony_ci 12013498266Sopenharmony_ci memset(lookup, 0xff, sizeof(lookup)); 12113498266Sopenharmony_ci memcpy(&lookup['+'], decodetable, sizeof(decodetable)); 12213498266Sopenharmony_ci /* replaces 12313498266Sopenharmony_ci { 12413498266Sopenharmony_ci unsigned char c; 12513498266Sopenharmony_ci const unsigned char *p = (const unsigned char *)base64encdec; 12613498266Sopenharmony_ci for(c = 0; *p; c++, p++) 12713498266Sopenharmony_ci lookup[*p] = c; 12813498266Sopenharmony_ci } 12913498266Sopenharmony_ci */ 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci /* Decode the complete quantums first */ 13213498266Sopenharmony_ci for(i = 0; i < fullQuantums; i++) { 13313498266Sopenharmony_ci unsigned char val; 13413498266Sopenharmony_ci unsigned int x = 0; 13513498266Sopenharmony_ci int j; 13613498266Sopenharmony_ci 13713498266Sopenharmony_ci for(j = 0; j < 4; j++) { 13813498266Sopenharmony_ci val = lookup[(unsigned char)*src++]; 13913498266Sopenharmony_ci if(val == 0xff) /* bad symbol */ 14013498266Sopenharmony_ci goto bad; 14113498266Sopenharmony_ci x = (x << 6) | val; 14213498266Sopenharmony_ci } 14313498266Sopenharmony_ci pos[2] = x & 0xff; 14413498266Sopenharmony_ci pos[1] = (x >> 8) & 0xff; 14513498266Sopenharmony_ci pos[0] = (x >> 16) & 0xff; 14613498266Sopenharmony_ci pos += 3; 14713498266Sopenharmony_ci } 14813498266Sopenharmony_ci if(padding) { 14913498266Sopenharmony_ci /* this means either 8 or 16 bits output */ 15013498266Sopenharmony_ci unsigned char val; 15113498266Sopenharmony_ci unsigned int x = 0; 15213498266Sopenharmony_ci int j; 15313498266Sopenharmony_ci size_t padc = 0; 15413498266Sopenharmony_ci for(j = 0; j < 4; j++) { 15513498266Sopenharmony_ci if(*src == '=') { 15613498266Sopenharmony_ci x <<= 6; 15713498266Sopenharmony_ci src++; 15813498266Sopenharmony_ci if(++padc > padding) 15913498266Sopenharmony_ci /* this is a badly placed '=' symbol! */ 16013498266Sopenharmony_ci goto bad; 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci else { 16313498266Sopenharmony_ci val = lookup[(unsigned char)*src++]; 16413498266Sopenharmony_ci if(val == 0xff) /* bad symbol */ 16513498266Sopenharmony_ci goto bad; 16613498266Sopenharmony_ci x = (x << 6) | val; 16713498266Sopenharmony_ci } 16813498266Sopenharmony_ci } 16913498266Sopenharmony_ci if(padding == 1) 17013498266Sopenharmony_ci pos[1] = (x >> 8) & 0xff; 17113498266Sopenharmony_ci pos[0] = (x >> 16) & 0xff; 17213498266Sopenharmony_ci pos += 3 - padding; 17313498266Sopenharmony_ci } 17413498266Sopenharmony_ci 17513498266Sopenharmony_ci /* Zero terminate */ 17613498266Sopenharmony_ci *pos = '\0'; 17713498266Sopenharmony_ci 17813498266Sopenharmony_ci /* Return the decoded data */ 17913498266Sopenharmony_ci *outptr = newstr; 18013498266Sopenharmony_ci *outlen = rawlen; 18113498266Sopenharmony_ci 18213498266Sopenharmony_ci return CURLE_OK; 18313498266Sopenharmony_cibad: 18413498266Sopenharmony_ci free(newstr); 18513498266Sopenharmony_ci return CURLE_BAD_CONTENT_ENCODING; 18613498266Sopenharmony_ci} 18713498266Sopenharmony_ci 18813498266Sopenharmony_cistatic CURLcode base64_encode(const char *table64, 18913498266Sopenharmony_ci const char *inputbuff, size_t insize, 19013498266Sopenharmony_ci char **outptr, size_t *outlen) 19113498266Sopenharmony_ci{ 19213498266Sopenharmony_ci char *output; 19313498266Sopenharmony_ci char *base64data; 19413498266Sopenharmony_ci const unsigned char *in = (unsigned char *)inputbuff; 19513498266Sopenharmony_ci const char *padstr = &table64[64]; /* Point to padding string. */ 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci *outptr = NULL; 19813498266Sopenharmony_ci *outlen = 0; 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci if(!insize) 20113498266Sopenharmony_ci insize = strlen(inputbuff); 20213498266Sopenharmony_ci 20313498266Sopenharmony_ci#if SIZEOF_SIZE_T == 4 20413498266Sopenharmony_ci if(insize > UINT_MAX/4) 20513498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 20613498266Sopenharmony_ci#endif 20713498266Sopenharmony_ci 20813498266Sopenharmony_ci base64data = output = malloc((insize + 2) / 3 * 4 + 1); 20913498266Sopenharmony_ci if(!output) 21013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 21113498266Sopenharmony_ci 21213498266Sopenharmony_ci while(insize >= 3) { 21313498266Sopenharmony_ci *output++ = table64[ in[0] >> 2 ]; 21413498266Sopenharmony_ci *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ]; 21513498266Sopenharmony_ci *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ]; 21613498266Sopenharmony_ci *output++ = table64[ in[2] & 0x3F ]; 21713498266Sopenharmony_ci insize -= 3; 21813498266Sopenharmony_ci in += 3; 21913498266Sopenharmony_ci } 22013498266Sopenharmony_ci if(insize) { 22113498266Sopenharmony_ci /* this is only one or two bytes now */ 22213498266Sopenharmony_ci *output++ = table64[ in[0] >> 2 ]; 22313498266Sopenharmony_ci if(insize == 1) { 22413498266Sopenharmony_ci *output++ = table64[ ((in[0] & 0x03) << 4) ]; 22513498266Sopenharmony_ci if(*padstr) { 22613498266Sopenharmony_ci *output++ = *padstr; 22713498266Sopenharmony_ci *output++ = *padstr; 22813498266Sopenharmony_ci } 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci else { 23113498266Sopenharmony_ci /* insize == 2 */ 23213498266Sopenharmony_ci *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ]; 23313498266Sopenharmony_ci *output++ = table64[ ((in[1] & 0x0F) << 2) ]; 23413498266Sopenharmony_ci if(*padstr) 23513498266Sopenharmony_ci *output++ = *padstr; 23613498266Sopenharmony_ci } 23713498266Sopenharmony_ci } 23813498266Sopenharmony_ci 23913498266Sopenharmony_ci /* Zero terminate */ 24013498266Sopenharmony_ci *output = '\0'; 24113498266Sopenharmony_ci 24213498266Sopenharmony_ci /* Return the pointer to the new data (allocated memory) */ 24313498266Sopenharmony_ci *outptr = base64data; 24413498266Sopenharmony_ci 24513498266Sopenharmony_ci /* Return the length of the new data */ 24613498266Sopenharmony_ci *outlen = output - base64data; 24713498266Sopenharmony_ci 24813498266Sopenharmony_ci return CURLE_OK; 24913498266Sopenharmony_ci} 25013498266Sopenharmony_ci 25113498266Sopenharmony_ci/* 25213498266Sopenharmony_ci * Curl_base64_encode() 25313498266Sopenharmony_ci * 25413498266Sopenharmony_ci * Given a pointer to an input buffer and an input size, encode it and 25513498266Sopenharmony_ci * return a pointer in *outptr to a newly allocated memory area holding 25613498266Sopenharmony_ci * encoded data. Size of encoded data is returned in variable pointed by 25713498266Sopenharmony_ci * outlen. 25813498266Sopenharmony_ci * 25913498266Sopenharmony_ci * Input length of 0 indicates input buffer holds a NUL-terminated string. 26013498266Sopenharmony_ci * 26113498266Sopenharmony_ci * Returns CURLE_OK on success, otherwise specific error code. Function 26213498266Sopenharmony_ci * output shall not be considered valid unless CURLE_OK is returned. 26313498266Sopenharmony_ci * 26413498266Sopenharmony_ci * @unittest: 1302 26513498266Sopenharmony_ci */ 26613498266Sopenharmony_ciCURLcode Curl_base64_encode(const char *inputbuff, size_t insize, 26713498266Sopenharmony_ci char **outptr, size_t *outlen) 26813498266Sopenharmony_ci{ 26913498266Sopenharmony_ci return base64_encode(base64encdec, inputbuff, insize, outptr, outlen); 27013498266Sopenharmony_ci} 27113498266Sopenharmony_ci 27213498266Sopenharmony_ci/* 27313498266Sopenharmony_ci * Curl_base64url_encode() 27413498266Sopenharmony_ci * 27513498266Sopenharmony_ci * Given a pointer to an input buffer and an input size, encode it and 27613498266Sopenharmony_ci * return a pointer in *outptr to a newly allocated memory area holding 27713498266Sopenharmony_ci * encoded data. Size of encoded data is returned in variable pointed by 27813498266Sopenharmony_ci * outlen. 27913498266Sopenharmony_ci * 28013498266Sopenharmony_ci * Input length of 0 indicates input buffer holds a NUL-terminated string. 28113498266Sopenharmony_ci * 28213498266Sopenharmony_ci * Returns CURLE_OK on success, otherwise specific error code. Function 28313498266Sopenharmony_ci * output shall not be considered valid unless CURLE_OK is returned. 28413498266Sopenharmony_ci * 28513498266Sopenharmony_ci * @unittest: 1302 28613498266Sopenharmony_ci */ 28713498266Sopenharmony_ciCURLcode Curl_base64url_encode(const char *inputbuff, size_t insize, 28813498266Sopenharmony_ci char **outptr, size_t *outlen) 28913498266Sopenharmony_ci{ 29013498266Sopenharmony_ci return base64_encode(base64url, inputbuff, insize, outptr, outlen); 29113498266Sopenharmony_ci} 29213498266Sopenharmony_ci 29313498266Sopenharmony_ci#endif /* no users so disabled */ 294