Skip to content

Commit fb4a98f

Browse files
jpfrPro
authored andcommitted
JSON: Switch to another base64 implementation after oss-fuzz problems
1 parent a06a792 commit fb4a98f

5 files changed

Lines changed: 126 additions & 224 deletions

File tree

deps/base64.c

Lines changed: 88 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,104 @@
11
/*
2-
3-
https://github.com/superwills/NibbleAndAHalf
4-
base64.h -- Fast base64 encoding and decoding.
5-
version 1.0.0, April 17, 2013 143a
6-
7-
Copyright (C) 2013 William Sherif
8-
9-
This software is provided 'as-is', without any express or implied
10-
warranty. In no event will the authors be held liable for any damages
11-
arising from the use of this software.
12-
13-
Permission is granted to anyone to use this software for any purpose,
14-
including commercial applications, and to alter it and redistribute it
15-
freely, subject to the following restrictions:
16-
17-
1. The origin of this software must not be misrepresented; you must not
18-
claim that you wrote the original software. If you use this software
19-
in a product, an acknowledgment in the product documentation would be
20-
appreciated but is not required.
21-
2. Altered source versions must be plainly marked as such, and must not be
22-
misrepresented as being the original software.
23-
3. This notice may not be removed or altered from any source distribution.
24-
25-
William Sherif
26-
will.sherif@gmail.com
27-
28-
YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
29-
30-
*/
2+
* Base64 encoding: Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
3+
* This software may be distributed under the terms of the BSD license.
4+
*
5+
* Base64 decoding: Copyright (c) 2016, polfosol
6+
* Posted at https://stackoverflow.com/a/37109258 under the CC-BY-SA Creative
7+
* Commons license.
8+
*/
319

3210
#include "base64.h"
11+
#include <open62541/types.h>
3312

34-
#include <stdio.h>
35-
#include <stdlib.h>
36-
37-
static const char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
38-
39-
// maps A=>0,B=>1..
40-
static const unsigned char unb64[]={
41-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
42-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
43-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
44-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
45-
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
46-
54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
47-
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
48-
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
49-
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
50-
25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
51-
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
52-
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
53-
49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
54-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
55-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
56-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
57-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
58-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
59-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
60-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
61-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
62-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
63-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
64-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
65-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
66-
0, 0, 0, 0, 0, 0,
67-
}; // This array has 256 elements
68-
69-
// Converts binary data of length=len to base64 characters.
70-
// Length of the resultant string is stored in flen
71-
// (you must pass pointer flen).
72-
char* UA_base64( const void* binaryData, int len, int *flen )
73-
{
74-
const unsigned char* bin = (const unsigned char*) binaryData ;
75-
char* res ;
76-
77-
int rc = 0 ; // result counter
78-
int byteNo ; // I need this after the loop
79-
80-
int modulusLen = len % 3 ;
81-
int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0.
13+
static const unsigned char base64_table[65] =
14+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
8215

83-
*flen = 4*(len + pad)/3 ;
84-
res = (char*) malloc( (size_t)(*flen + 1) ) ; // and one for the null
85-
if( !res )
86-
{
87-
puts( "ERROR: base64 could not allocate enough memory." ) ;
88-
puts( "I must stop because I could not get enough" ) ;
89-
return 0;
16+
unsigned char *
17+
UA_base64(const unsigned char *src, size_t len, size_t *out_len) {
18+
if(len == 0) {
19+
*out_len = 0;
20+
return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
9021
}
9122

92-
for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 )
93-
{
94-
unsigned char BYTE0=bin[byteNo];
95-
unsigned char BYTE1=bin[byteNo+1];
96-
unsigned char BYTE2=bin[byteNo+2];
97-
res[rc++] = b64[ BYTE0 >> 2 ] ;
98-
res[rc++] = b64[ ((0x3&BYTE0)<<4) + (BYTE1 >> 4) ] ;
99-
res[rc++] = b64[ ((0x0f&BYTE1)<<2) + (BYTE2>>6) ] ;
100-
res[rc++] = b64[ 0x3f&BYTE2 ] ;
101-
}
102-
103-
if( pad==2 )
104-
{
105-
res[rc++] = b64[ bin[byteNo] >> 2 ] ;
106-
res[rc++] = b64[ (0x3&bin[byteNo])<<4 ] ;
107-
res[rc++] = '=';
108-
res[rc++] = '=';
109-
}
110-
else if( pad==1 )
111-
{
112-
res[rc++] = b64[ bin[byteNo] >> 2 ] ;
113-
res[rc++] = b64[ ((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4) ] ;
114-
res[rc++] = b64[ (0x0f&bin[byteNo+1])<<2 ] ;
115-
res[rc++] = '=';
116-
}
117-
118-
res[rc]=0; // NULL TERMINATOR! ;)
119-
return res ;
23+
size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
24+
if(olen < len)
25+
return NULL; /* integer overflow */
26+
27+
unsigned char *out = (unsigned char*)UA_malloc(olen);
28+
if(!out)
29+
return NULL;
30+
31+
const unsigned char *end = src + len;
32+
const unsigned char *in = src;
33+
unsigned char *pos = out;
34+
while(end - in >= 3) {
35+
*pos++ = base64_table[in[0] >> 2];
36+
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
37+
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
38+
*pos++ = base64_table[in[2] & 0x3f];
39+
in += 3;
40+
}
41+
42+
if(end - in) {
43+
*pos++ = base64_table[in[0] >> 2];
44+
if(end - in == 1) {
45+
*pos++ = base64_table[(in[0] & 0x03) << 4];
46+
*pos++ = '=';
47+
} else {
48+
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
49+
*pos++ = base64_table[(in[1] & 0x0f) << 2];
50+
}
51+
*pos++ = '=';
52+
}
53+
54+
*out_len = (size_t)(pos - out);
55+
return out;
12056
}
12157

122-
unsigned char* UA_unbase64( const char* ascii, int len, int *flen )
123-
{
124-
const unsigned char *safeAsciiPtr = (const unsigned char*)ascii ;
125-
unsigned char *bin ;
126-
int cb=0;
127-
int charNo;
128-
int pad = 0 ;
129-
130-
if( len < 2 ) { // 2 accesses below would be OOB.
131-
// catch empty string, return NULL as result.
132-
puts( "ERROR: You passed an invalid base64 string (too short). You get NULL back." ) ;
133-
*flen=0;
134-
return 0 ;
58+
static const uint32_t from_b64[256] = {
59+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63,
62+
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
63+
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
64+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63,
65+
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
66+
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
67+
68+
unsigned char *
69+
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) {
70+
if(len == 0) {
71+
*out_len = 0;
72+
return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
13573
}
136-
if( safeAsciiPtr[ len-1 ]=='=' ) ++pad ;
137-
if( safeAsciiPtr[ len-2 ]=='=' ) ++pad ;
13874

139-
*flen = 3*len/4 - pad ;
140-
bin = (unsigned char*)malloc( (size_t) (*flen) ) ;
141-
if( !bin )
142-
{
143-
puts( "ERROR: unbase64 could not allocate enough memory." ) ;
144-
puts( "I must stop because I could not get enough" ) ;
145-
return 0;
75+
const unsigned char *p = src;
76+
size_t pad1 = len % 4 || p[len - 1] == '=';
77+
size_t pad2 = pad1 && (len % 4 > 2 || p[len - 2] != '=');
78+
const size_t last = (len - pad1) / 4 << 2;
79+
80+
unsigned char *str = (unsigned char*)UA_malloc(last / 4 * 3 + pad1 + pad2);
81+
if(!str)
82+
return NULL;
83+
84+
unsigned char *pos = str;
85+
for(size_t i = 0; i < last; i += 4) {
86+
uint32_t n = from_b64[p[i]] << 18 | from_b64[p[i + 1]] << 12 |
87+
from_b64[p[i + 2]] << 6 | from_b64[p[i + 3]];
88+
*pos++ = (unsigned char)(n >> 16);
89+
*pos++ = (unsigned char)(n >> 8 & 0xFF);
90+
*pos++ = (unsigned char)(n & 0xFF);
14691
}
14792

148-
for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 )
149-
{
150-
int A=unb64[safeAsciiPtr[charNo]];
151-
int B=unb64[safeAsciiPtr[charNo+1]];
152-
int C=unb64[safeAsciiPtr[charNo+2]];
153-
int D=unb64[safeAsciiPtr[charNo+3]];
154-
155-
bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
156-
bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ;
157-
bin[cb++] = (unsigned char)((C<<6) | (D)) ;
93+
if(pad1) {
94+
uint32_t n = from_b64[p[last]] << 18 | from_b64[p[last + 1]] << 12;
95+
*pos++ = (unsigned char)(n >> 16);
96+
if(pad2) {
97+
n |= from_b64[p[last + 2]] << 6;
98+
*pos++ = (unsigned char)(n >> 8 & 0xFF);
99+
}
158100
}
159101

160-
if( pad==1 )
161-
{
162-
int A=unb64[safeAsciiPtr[charNo]];
163-
int B=unb64[safeAsciiPtr[charNo+1]];
164-
int C=unb64[safeAsciiPtr[charNo+2]];
165-
166-
bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
167-
bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ;
168-
}
169-
else if( pad==2 )
170-
{
171-
int A=unb64[safeAsciiPtr[charNo]];
172-
int B=unb64[safeAsciiPtr[charNo+1]];
173-
174-
bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
175-
}
176-
177-
return bin ;
102+
*out_len = (uintptr_t)(pos - str);
103+
return str;
178104
}
179-

deps/base64.h

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,32 @@
1-
/*
2-
3-
https://github.com/superwills/NibbleAndAHalf
4-
base64.h -- Fast base64 encoding and decoding.
5-
version 1.0.0, April 17, 2013 143a
6-
7-
Copyright (C) 2013 William Sherif
8-
9-
This software is provided 'as-is', without any express or implied
10-
warranty. In no event will the authors be held liable for any damages
11-
arising from the use of this software.
12-
13-
Permission is granted to anyone to use this software for any purpose,
14-
including commercial applications, and to alter it and redistribute it
15-
freely, subject to the following restrictions:
16-
17-
1. The origin of this software must not be misrepresented; you must not
18-
claim that you wrote the original software. If you use this software
19-
in a product, an acknowledgment in the product documentation would be
20-
appreciated but is not required.
21-
2. Altered source versions must be plainly marked as such, and must not be
22-
misrepresented as being the original software.
23-
3. This notice may not be removed or altered from any source distribution.
24-
25-
William Sherif
26-
will.sherif@gmail.com
27-
28-
YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
29-
30-
*/
311
#ifndef UA_BASE64_H_
322
#define UA_BASE64_H_
333

34-
#ifdef __cplusplus
35-
extern "C" {
36-
#endif
37-
38-
char* UA_base64( const void* binaryData, int len, int *flen );
39-
40-
unsigned char* UA_unbase64( const char* ascii, int len, int *flen );
41-
42-
#ifdef __cplusplus
43-
}
44-
#endif
4+
#include <open62541/config.h>
5+
6+
_UA_BEGIN_DECLS
7+
8+
#include <stddef.h>
9+
10+
/**
11+
* base64_encode - Base64 encode
12+
* @src: Data to be encoded
13+
* @len: Length of the data to be encoded
14+
* @out_len: Pointer to output length variable
15+
* Returns: Allocated buffer of out_len bytes of encoded data,
16+
* or %NULL on failure. The output is NOT Null-terminated. */
17+
unsigned char *
18+
UA_base64(const unsigned char *src, size_t len, size_t *out_len);
19+
20+
/**
21+
* base64_decode - Base64 decode
22+
* @src: Data to be decoded
23+
* @len: Length of the data to be decoded
24+
* @out_len: Pointer to output length variable
25+
* Returns: Allocated buffer of out_len bytes of decoded data,
26+
* or %NULL on failure. */
27+
unsigned char *
28+
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len);
29+
30+
_UA_END_DECLS
4531

4632
#endif /* UA_BASE64_H_ */

src/ua_types_encoding_json.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -656,27 +656,21 @@ ENCODE_JSON(ByteString) {
656656
}
657657

658658
status ret = writeJsonQuote(ctx);
659-
int flen;
660-
char *ba64 = UA_base64(src->data, (int)src->length, &flen);
659+
size_t flen = 0;
660+
unsigned char *ba64 = UA_base64(src->data, src->length, &flen);
661661

662662
/* Not converted, no mem */
663663
if(!ba64)
664664
return UA_STATUSCODE_BADENCODINGERROR;
665665

666-
/* Check if negative... (TODO: Why is base64 3rd argument type int?) */
667-
if(flen < 0) {
668-
UA_free(ba64);
669-
return UA_STATUSCODE_BADENCODINGERROR;
670-
}
671-
672666
if(ctx->pos + flen > ctx->end) {
673667
UA_free(ba64);
674668
return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
675669
}
676670

677671
/* Copy flen bytes to output stream. */
678672
if(!ctx->calcOnly)
679-
memcpy(ctx->pos, ba64, (size_t)flen);
673+
memcpy(ctx->pos, ba64, flen);
680674
ctx->pos += flen;
681675

682676
/* Base64 result no longer needed */
@@ -2205,13 +2199,13 @@ DECODE_JSON(ByteString) {
22052199
return UA_STATUSCODE_GOOD;
22062200
}
22072201

2208-
int flen;
2209-
unsigned char* unB64 = UA_unbase64(tokenData, (int)tokenSize, &flen);
2202+
size_t flen = 0;
2203+
unsigned char* unB64 = UA_unbase64((unsigned char*)tokenData, tokenSize, &flen);
22102204
if(unB64 == 0)
22112205
return UA_STATUSCODE_BADDECODINGERROR;
22122206

22132207
dst->data = (u8*)unB64;
2214-
dst->length = (size_t)flen;
2208+
dst->length = flen;
22152209

22162210
if(moveToken)
22172211
parseCtx->index++;

0 commit comments

Comments
 (0)